diff options
Diffstat (limited to '')
60 files changed, 20113 insertions, 3154 deletions
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs new file mode 100644 index 0000000..d91c47f --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs | |||
@@ -0,0 +1,814 @@ | |||
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.BulletSNPlugin | ||
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 OMV.Vector3 _position; | ||
47 | private float _mass; | ||
48 | private float _avatarDensity; | ||
49 | private float _avatarVolume; | ||
50 | private OMV.Vector3 _force; | ||
51 | private OMV.Vector3 _velocity; | ||
52 | private OMV.Vector3 _torque; | ||
53 | private float _collisionScore; | ||
54 | private OMV.Vector3 _acceleration; | ||
55 | private OMV.Quaternion _orientation; | ||
56 | private int _physicsActorType; | ||
57 | private bool _isPhysical; | ||
58 | private bool _flying; | ||
59 | private bool _setAlwaysRun; | ||
60 | private bool _throttleUpdates; | ||
61 | private bool _isColliding; | ||
62 | private bool _collidingObj; | ||
63 | private bool _floatOnWater; | ||
64 | private OMV.Vector3 _rotationalVelocity; | ||
65 | private bool _kinematic; | ||
66 | private float _buoyancy; | ||
67 | |||
68 | // The friction and velocity of the avatar is modified depending on whether walking or not. | ||
69 | private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar | ||
70 | private float _currentFriction; // the friction currently being used (changed by setVelocity). | ||
71 | |||
72 | private BSVMotor _velocityMotor; | ||
73 | |||
74 | private OMV.Vector3 _PIDTarget; | ||
75 | private bool _usePID; | ||
76 | private float _PIDTau; | ||
77 | private bool _useHoverPID; | ||
78 | private float _PIDHoverHeight; | ||
79 | private PIDHoverType _PIDHoverType; | ||
80 | private float _PIDHoverTao; | ||
81 | |||
82 | public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) | ||
83 | : base(parent_scene, localID, avName, "BSCharacter") | ||
84 | { | ||
85 | _physicsActorType = (int)ActorTypes.Agent; | ||
86 | _position = pos; | ||
87 | |||
88 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||
89 | // replace with the default values. | ||
90 | _size = size; | ||
91 | if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; | ||
92 | if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; | ||
93 | |||
94 | // A motor to control the acceleration and deceleration of the avatar movement. | ||
95 | // _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); | ||
96 | // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); | ||
97 | // Infinite decay and timescale values so motor only changes current to target values. | ||
98 | _velocityMotor = new BSVMotor("BSCharacter.Velocity", | ||
99 | 0.2f, // time scale | ||
100 | BSMotor.Infinite, // decay time scale | ||
101 | BSMotor.InfiniteVector, // friction timescale | ||
102 | 1f // efficiency | ||
103 | ); | ||
104 | _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
105 | |||
106 | _flying = isFlying; | ||
107 | _orientation = OMV.Quaternion.Identity; | ||
108 | _velocity = OMV.Vector3.Zero; | ||
109 | _appliedVelocity = OMV.Vector3.Zero; | ||
110 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); | ||
111 | _currentFriction = BSParam.AvatarStandingFriction; | ||
112 | _avatarDensity = BSParam.AvatarDensity; | ||
113 | |||
114 | // The dimensions of the avatar capsule are kept in the scale. | ||
115 | // Physics creates a unit capsule which is scaled by the physics engine. | ||
116 | ComputeAvatarScale(_size); | ||
117 | // set _avatarVolume and _mass based on capsule size, _density and Scale | ||
118 | ComputeAvatarVolumeAndMass(); | ||
119 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | ||
120 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | ||
121 | |||
122 | // do actual creation in taint time | ||
123 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | ||
124 | { | ||
125 | DetailLog("{0},BSCharacter.create,taint", LocalID); | ||
126 | // New body and shape into PhysBody and PhysShape | ||
127 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); | ||
128 | |||
129 | SetPhysicalProperties(); | ||
130 | }); | ||
131 | return; | ||
132 | } | ||
133 | |||
134 | // called when this character is being destroyed and the resources should be released | ||
135 | public override void Destroy() | ||
136 | { | ||
137 | base.Destroy(); | ||
138 | |||
139 | DetailLog("{0},BSCharacter.Destroy", LocalID); | ||
140 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | ||
141 | { | ||
142 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | ||
143 | PhysBody.Clear(); | ||
144 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | ||
145 | PhysShape.Clear(); | ||
146 | }); | ||
147 | } | ||
148 | |||
149 | private void SetPhysicalProperties() | ||
150 | { | ||
151 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | ||
152 | |||
153 | ZeroMotion(true); | ||
154 | ForcePosition = _position; | ||
155 | // Set the velocity and compute the proper friction | ||
156 | ForceVelocity = _velocity; | ||
157 | // Setting the current and target in the motor will cause it to start computing any deceleration. | ||
158 | _velocityMotor.Reset(); | ||
159 | _velocityMotor.SetCurrent(_velocity); | ||
160 | _velocityMotor.SetTarget(_velocity); | ||
161 | _velocityMotor.Enabled = false; | ||
162 | |||
163 | // This will enable or disable the flying buoyancy of the avatar. | ||
164 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. | ||
165 | Flying = _flying; | ||
166 | |||
167 | BulletSimAPI.SetRestitution2(PhysBody.ptr, BSParam.AvatarRestitution); | ||
168 | BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); | ||
169 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | ||
170 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold); | ||
171 | if (BSParam.CcdMotionThreshold > 0f) | ||
172 | { | ||
173 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold); | ||
174 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius); | ||
175 | } | ||
176 | |||
177 | UpdatePhysicalMassProperties(RawMass, false); | ||
178 | |||
179 | // Make so capsule does not fall over | ||
180 | BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero); | ||
181 | |||
182 | BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); | ||
183 | |||
184 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr, _position, _orientation); | ||
185 | |||
186 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); | ||
187 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION); | ||
188 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | ||
189 | |||
190 | // Do this after the object has been added to the world | ||
191 | PhysBody.collisionType = CollisionType.Avatar; | ||
192 | PhysBody.ApplyCollisionMask(); | ||
193 | } | ||
194 | |||
195 | public override void RequestPhysicsterseUpdate() | ||
196 | { | ||
197 | base.RequestPhysicsterseUpdate(); | ||
198 | } | ||
199 | // No one calls this method so I don't know what it could possibly mean | ||
200 | public override bool Stopped { get { return false; } } | ||
201 | |||
202 | public override OMV.Vector3 Size { | ||
203 | get | ||
204 | { | ||
205 | // Avatar capsule size is kept in the scale parameter. | ||
206 | return _size; | ||
207 | } | ||
208 | |||
209 | set { | ||
210 | // When an avatar's size is set, only the height is changed. | ||
211 | _size = value; | ||
212 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||
213 | // replace with the default values. | ||
214 | if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; | ||
215 | if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; | ||
216 | |||
217 | ComputeAvatarScale(_size); | ||
218 | ComputeAvatarVolumeAndMass(); | ||
219 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", | ||
220 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | ||
221 | |||
222 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | ||
223 | { | ||
224 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) | ||
225 | { | ||
226 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | ||
227 | UpdatePhysicalMassProperties(RawMass, true); | ||
228 | // Make sure this change appears as a property update event | ||
229 | BulletSimAPI.PushUpdate2(PhysBody.ptr); | ||
230 | } | ||
231 | }); | ||
232 | |||
233 | } | ||
234 | } | ||
235 | |||
236 | public override PrimitiveBaseShape Shape | ||
237 | { | ||
238 | set { BaseShape = value; } | ||
239 | } | ||
240 | // I want the physics engine to make an avatar capsule | ||
241 | public override BSPhysicsShapeType PreferredPhysicalShape | ||
242 | { | ||
243 | get {return BSPhysicsShapeType.SHAPE_CAPSULE; } | ||
244 | } | ||
245 | |||
246 | public override bool Grabbed { | ||
247 | set { _grabbed = value; } | ||
248 | } | ||
249 | public override bool Selected { | ||
250 | set { _selected = value; } | ||
251 | } | ||
252 | public override void CrossingFailure() { return; } | ||
253 | public override void link(PhysicsActor obj) { return; } | ||
254 | public override void delink() { return; } | ||
255 | |||
256 | // Set motion values to zero. | ||
257 | // Do it to the properties so the values get set in the physics engine. | ||
258 | // Push the setting of the values to the viewer. | ||
259 | // Called at taint time! | ||
260 | public override void ZeroMotion(bool inTaintTime) | ||
261 | { | ||
262 | _velocity = OMV.Vector3.Zero; | ||
263 | _acceleration = OMV.Vector3.Zero; | ||
264 | _rotationalVelocity = OMV.Vector3.Zero; | ||
265 | |||
266 | // Zero some other properties directly into the physics engine | ||
267 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | ||
268 | { | ||
269 | if (PhysBody.HasPhysicalBody) | ||
270 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | ||
271 | }); | ||
272 | } | ||
273 | public override void ZeroAngularMotion(bool inTaintTime) | ||
274 | { | ||
275 | _rotationalVelocity = OMV.Vector3.Zero; | ||
276 | |||
277 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | ||
278 | { | ||
279 | if (PhysBody.HasPhysicalBody) | ||
280 | { | ||
281 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | ||
282 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | ||
283 | // The next also get rid of applied linear force but the linear velocity is untouched. | ||
284 | BulletSimAPI.ClearForces2(PhysBody.ptr); | ||
285 | } | ||
286 | }); | ||
287 | } | ||
288 | |||
289 | |||
290 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } | ||
291 | |||
292 | public override OMV.Vector3 RawPosition | ||
293 | { | ||
294 | get { return _position; } | ||
295 | set { _position = value; } | ||
296 | } | ||
297 | public override OMV.Vector3 Position { | ||
298 | get { | ||
299 | // Don't refetch the position because this function is called a zillion times | ||
300 | // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); | ||
301 | return _position; | ||
302 | } | ||
303 | set { | ||
304 | _position = value; | ||
305 | PositionSanityCheck(); | ||
306 | |||
307 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | ||
308 | { | ||
309 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
310 | if (PhysBody.HasPhysicalBody) | ||
311 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
312 | }); | ||
313 | } | ||
314 | } | ||
315 | public override OMV.Vector3 ForcePosition { | ||
316 | get { | ||
317 | _position = BulletSimAPI.GetPosition2(PhysBody.ptr); | ||
318 | return _position; | ||
319 | } | ||
320 | set { | ||
321 | _position = value; | ||
322 | PositionSanityCheck(); | ||
323 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | |||
328 | // Check that the current position is sane and, if not, modify the position to make it so. | ||
329 | // Check for being below terrain or on water. | ||
330 | // Returns 'true' of the position was made sane by some action. | ||
331 | private bool PositionSanityCheck() | ||
332 | { | ||
333 | bool ret = false; | ||
334 | |||
335 | // TODO: check for out of bounds | ||
336 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) | ||
337 | { | ||
338 | // The character is out of the known/simulated area. | ||
339 | // Upper levels of code will handle the transition to other areas so, for | ||
340 | // the time, we just ignore the position. | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | // If below the ground, move the avatar up | ||
345 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | ||
346 | if (Position.Z < terrainHeight) | ||
347 | { | ||
348 | DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | ||
349 | _position.Z = terrainHeight + 2.0f; | ||
350 | ret = true; | ||
351 | } | ||
352 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | ||
353 | { | ||
354 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); | ||
355 | if (Position.Z < waterHeight) | ||
356 | { | ||
357 | _position.Z = waterHeight; | ||
358 | ret = true; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | return ret; | ||
363 | } | ||
364 | |||
365 | // A version of the sanity check that also makes sure a new position value is | ||
366 | // pushed back to the physics engine. This routine would be used by anyone | ||
367 | // who is not already pushing the value. | ||
368 | private bool PositionSanityCheck(bool inTaintTime) | ||
369 | { | ||
370 | bool ret = false; | ||
371 | if (PositionSanityCheck()) | ||
372 | { | ||
373 | // The new position value must be pushed into the physics engine but we can't | ||
374 | // just assign to "Position" because of potential call loops. | ||
375 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() | ||
376 | { | ||
377 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
378 | if (PhysBody.HasPhysicalBody) | ||
379 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
380 | }); | ||
381 | ret = true; | ||
382 | } | ||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | public override float Mass { get { return _mass; } } | ||
387 | |||
388 | // used when we only want this prim's mass and not the linkset thing | ||
389 | public override float RawMass { | ||
390 | get {return _mass; } | ||
391 | } | ||
392 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) | ||
393 | { | ||
394 | OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); | ||
395 | BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); | ||
396 | } | ||
397 | |||
398 | public override OMV.Vector3 Force { | ||
399 | get { return _force; } | ||
400 | set { | ||
401 | _force = value; | ||
402 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); | ||
403 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | ||
404 | { | ||
405 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | ||
406 | if (PhysBody.HasPhysicalBody) | ||
407 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | ||
408 | }); | ||
409 | } | ||
410 | } | ||
411 | |||
412 | public bool TouchingGround() | ||
413 | { | ||
414 | bool ret = BulletSimAPI.RayCastGround(PhysicsScene.World.ptr,_position,_size.Z * 0.55f, PhysBody.ptr); | ||
415 | return ret; | ||
416 | } | ||
417 | // Avatars don't do vehicles | ||
418 | public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } } | ||
419 | public override void VehicleFloatParam(int param, float value) { } | ||
420 | public override void VehicleVectorParam(int param, OMV.Vector3 value) {} | ||
421 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } | ||
422 | public override void VehicleFlags(int param, bool remove) { } | ||
423 | |||
424 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | ||
425 | public override void SetVolumeDetect(int param) { return; } | ||
426 | |||
427 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } | ||
428 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } | ||
429 | |||
430 | // Sets the target in the motor. This starts the changing of the avatar's velocity. | ||
431 | public override OMV.Vector3 TargetVelocity | ||
432 | { | ||
433 | get | ||
434 | { | ||
435 | return _velocityMotor.TargetValue; | ||
436 | } | ||
437 | set | ||
438 | { | ||
439 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); | ||
440 | |||
441 | if (!_flying) | ||
442 | if ((value.Z >= 0.0001f) || (value.Z <= -0.0001f) || _velocity.Z < -0.0001f) | ||
443 | if (!TouchingGround()) | ||
444 | value.Z = _velocity.Z; | ||
445 | if (_setAlwaysRun) | ||
446 | value *= 1.3f; | ||
447 | |||
448 | OMV.Vector3 targetVel = value; | ||
449 | |||
450 | PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() | ||
451 | { | ||
452 | |||
453 | _velocityMotor.Reset(); | ||
454 | _velocityMotor.SetTarget(targetVel); | ||
455 | _velocityMotor.SetCurrent(_velocity); | ||
456 | _velocityMotor.Enabled = true; | ||
457 | |||
458 | // Make sure a property update happens next step so the motor gets incorporated. | ||
459 | BulletSimAPI.PushUpdate2(PhysBody.ptr); | ||
460 | }); | ||
461 | } | ||
462 | } | ||
463 | // Directly setting velocity means this is what the user really wants now. | ||
464 | public override OMV.Vector3 Velocity { | ||
465 | get { return _velocity; } | ||
466 | set { | ||
467 | _velocity = value; | ||
468 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); | ||
469 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() | ||
470 | { | ||
471 | _velocityMotor.Reset(); | ||
472 | _velocityMotor.SetCurrent(_velocity); | ||
473 | _velocityMotor.SetTarget(_velocity); | ||
474 | // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar. | ||
475 | _velocityMotor.Enabled = false; | ||
476 | |||
477 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); | ||
478 | ForceVelocity = _velocity; | ||
479 | }); | ||
480 | } | ||
481 | } | ||
482 | public override OMV.Vector3 ForceVelocity { | ||
483 | get { return _velocity; } | ||
484 | set { | ||
485 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); | ||
486 | |||
487 | _velocity = value; | ||
488 | // Depending on whether the avatar is moving or not, change the friction | ||
489 | // to keep the avatar from slipping around | ||
490 | if (_velocity.Length() == 0) | ||
491 | { | ||
492 | if (_currentFriction != BSParam.AvatarStandingFriction) | ||
493 | { | ||
494 | _currentFriction = BSParam.AvatarStandingFriction; | ||
495 | if (PhysBody.HasPhysicalBody) | ||
496 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | ||
497 | } | ||
498 | } | ||
499 | else | ||
500 | { | ||
501 | if (_currentFriction != BSParam.AvatarFriction) | ||
502 | { | ||
503 | _currentFriction = BSParam.AvatarFriction; | ||
504 | if (PhysBody.HasPhysicalBody) | ||
505 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | ||
506 | } | ||
507 | } | ||
508 | // Remember the set velocity so we can suppress the reduction by friction, ... | ||
509 | _appliedVelocity = value; | ||
510 | |||
511 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | ||
512 | BulletSimAPI.Activate2(PhysBody.ptr, true); | ||
513 | } | ||
514 | } | ||
515 | public override OMV.Vector3 Torque { | ||
516 | get { return _torque; } | ||
517 | set { _torque = value; | ||
518 | } | ||
519 | } | ||
520 | public override float CollisionScore { | ||
521 | get { return _collisionScore; } | ||
522 | set { _collisionScore = value; | ||
523 | } | ||
524 | } | ||
525 | public override OMV.Vector3 Acceleration { | ||
526 | get { return _acceleration; } | ||
527 | set { _acceleration = value; } | ||
528 | } | ||
529 | public override OMV.Quaternion RawOrientation | ||
530 | { | ||
531 | get { return _orientation; } | ||
532 | set { _orientation = value; } | ||
533 | } | ||
534 | public override OMV.Quaternion Orientation { | ||
535 | get { return _orientation; } | ||
536 | set { | ||
537 | _orientation = value; | ||
538 | // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); | ||
539 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | ||
540 | { | ||
541 | if (PhysBody.HasPhysicalBody) | ||
542 | { | ||
543 | // _position = BulletSimAPI.GetPosition2(BSBody.ptr); | ||
544 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
545 | } | ||
546 | }); | ||
547 | } | ||
548 | } | ||
549 | // Go directly to Bullet to get/set the value. | ||
550 | public override OMV.Quaternion ForceOrientation | ||
551 | { | ||
552 | get | ||
553 | { | ||
554 | _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); | ||
555 | return _orientation; | ||
556 | } | ||
557 | set | ||
558 | { | ||
559 | _orientation = value; | ||
560 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
561 | } | ||
562 | } | ||
563 | public override int PhysicsActorType { | ||
564 | get { return _physicsActorType; } | ||
565 | set { _physicsActorType = value; | ||
566 | } | ||
567 | } | ||
568 | public override bool IsPhysical { | ||
569 | get { return _isPhysical; } | ||
570 | set { _isPhysical = value; | ||
571 | } | ||
572 | } | ||
573 | public override bool IsSolid { | ||
574 | get { return true; } | ||
575 | } | ||
576 | public override bool IsStatic { | ||
577 | get { return false; } | ||
578 | } | ||
579 | public override bool Flying { | ||
580 | get { return _flying; } | ||
581 | set { | ||
582 | _flying = value; | ||
583 | |||
584 | // simulate flying by changing the effect of gravity | ||
585 | Buoyancy = ComputeBuoyancyFromFlying(_flying); | ||
586 | } | ||
587 | } | ||
588 | // Flying is implimented by changing the avatar's buoyancy. | ||
589 | // Would this be done better with a vehicle type? | ||
590 | private float ComputeBuoyancyFromFlying(bool ifFlying) { | ||
591 | return ifFlying ? 1f : 0f; | ||
592 | } | ||
593 | public override bool | ||
594 | SetAlwaysRun { | ||
595 | get { return _setAlwaysRun; } | ||
596 | set { _setAlwaysRun = value; } | ||
597 | } | ||
598 | public override bool ThrottleUpdates { | ||
599 | get { return _throttleUpdates; } | ||
600 | set { _throttleUpdates = value; } | ||
601 | } | ||
602 | public override bool IsColliding { | ||
603 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | ||
604 | set { _isColliding = value; } | ||
605 | } | ||
606 | public override bool CollidingGround { | ||
607 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | ||
608 | set { CollidingGround = value; } | ||
609 | } | ||
610 | public override bool CollidingObj { | ||
611 | get { return _collidingObj; } | ||
612 | set { _collidingObj = value; } | ||
613 | } | ||
614 | public override bool FloatOnWater { | ||
615 | set { | ||
616 | _floatOnWater = value; | ||
617 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() | ||
618 | { | ||
619 | if (PhysBody.HasPhysicalBody) | ||
620 | { | ||
621 | if (_floatOnWater) | ||
622 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | ||
623 | else | ||
624 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | ||
625 | } | ||
626 | }); | ||
627 | } | ||
628 | } | ||
629 | public override OMV.Vector3 RotationalVelocity { | ||
630 | get { return _rotationalVelocity; } | ||
631 | set { _rotationalVelocity = value; } | ||
632 | } | ||
633 | public override OMV.Vector3 ForceRotationalVelocity { | ||
634 | get { return _rotationalVelocity; } | ||
635 | set { _rotationalVelocity = value; } | ||
636 | } | ||
637 | public override bool Kinematic { | ||
638 | get { return _kinematic; } | ||
639 | set { _kinematic = value; } | ||
640 | } | ||
641 | // neg=fall quickly, 0=1g, 1=0g, pos=float up | ||
642 | public override float Buoyancy { | ||
643 | get { return _buoyancy; } | ||
644 | set { _buoyancy = value; | ||
645 | PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() | ||
646 | { | ||
647 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
648 | ForceBuoyancy = _buoyancy; | ||
649 | }); | ||
650 | } | ||
651 | } | ||
652 | public override float ForceBuoyancy { | ||
653 | get { return _buoyancy; } | ||
654 | set { | ||
655 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); | ||
656 | |||
657 | _buoyancy = value; | ||
658 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
659 | // Buoyancy is faked by changing the gravity applied to the object | ||
660 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | ||
661 | if (PhysBody.HasPhysicalBody) | ||
662 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | ||
663 | } | ||
664 | } | ||
665 | |||
666 | // Used for MoveTo | ||
667 | public override OMV.Vector3 PIDTarget { | ||
668 | set { _PIDTarget = value; } | ||
669 | } | ||
670 | public override bool PIDActive { | ||
671 | set { _usePID = value; } | ||
672 | } | ||
673 | public override float PIDTau { | ||
674 | set { _PIDTau = value; } | ||
675 | } | ||
676 | |||
677 | // Used for llSetHoverHeight and maybe vehicle height | ||
678 | // Hover Height will override MoveTo target's Z | ||
679 | public override bool PIDHoverActive { | ||
680 | set { _useHoverPID = value; } | ||
681 | } | ||
682 | public override float PIDHoverHeight { | ||
683 | set { _PIDHoverHeight = value; } | ||
684 | } | ||
685 | public override PIDHoverType PIDHoverType { | ||
686 | set { _PIDHoverType = value; } | ||
687 | } | ||
688 | public override float PIDHoverTau { | ||
689 | set { _PIDHoverTao = value; } | ||
690 | } | ||
691 | |||
692 | // For RotLookAt | ||
693 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
694 | public override bool APIDActive { set { return; } } | ||
695 | public override float APIDStrength { set { return; } } | ||
696 | public override float APIDDamping { set { return; } } | ||
697 | |||
698 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | ||
699 | if (force.IsFinite()) | ||
700 | { | ||
701 | _force.X += force.X; | ||
702 | _force.Y += force.Y; | ||
703 | _force.Z += force.Z; | ||
704 | // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); | ||
705 | PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() | ||
706 | { | ||
707 | DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); | ||
708 | if (PhysBody.HasPhysicalBody) | ||
709 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | ||
710 | }); | ||
711 | } | ||
712 | else | ||
713 | { | ||
714 | m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader); | ||
715 | } | ||
716 | //m_lastUpdateSent = false; | ||
717 | } | ||
718 | |||
719 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | ||
720 | } | ||
721 | public override void SetMomentum(OMV.Vector3 momentum) { | ||
722 | } | ||
723 | |||
724 | private void ComputeAvatarScale(OMV.Vector3 size) | ||
725 | { | ||
726 | OMV.Vector3 newScale = size; | ||
727 | // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; | ||
728 | // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; | ||
729 | |||
730 | // From the total height, remove the capsule half spheres that are at each end | ||
731 | // The 1.15f came from ODE. Not sure what this factors in. | ||
732 | // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y); | ||
733 | |||
734 | // The total scale height is the central cylindar plus the caps on the two ends. | ||
735 | newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f); | ||
736 | |||
737 | // Convert diameters to radii and height to half height -- the way Bullet expects it. | ||
738 | Scale = newScale / 2f; | ||
739 | } | ||
740 | |||
741 | // set _avatarVolume and _mass based on capsule size, _density and Scale | ||
742 | private void ComputeAvatarVolumeAndMass() | ||
743 | { | ||
744 | _avatarVolume = (float)( | ||
745 | Math.PI | ||
746 | * Scale.X | ||
747 | * Scale.Y // the area of capsule cylinder | ||
748 | * Scale.Z // times height of capsule cylinder | ||
749 | + 1.33333333f | ||
750 | * Math.PI | ||
751 | * Scale.X | ||
752 | * Math.Min(Scale.X, Scale.Y) | ||
753 | * Scale.Y // plus the volume of the capsule end caps | ||
754 | ); | ||
755 | _mass = _avatarDensity * _avatarVolume; | ||
756 | } | ||
757 | |||
758 | // The physics engine says that properties have updated. Update same and inform | ||
759 | // the world that things have changed. | ||
760 | public override void UpdateProperties(EntityProperties entprop) | ||
761 | { | ||
762 | _position = entprop.Position; | ||
763 | _orientation = entprop.Rotation; | ||
764 | _velocity = entprop.Velocity; | ||
765 | _acceleration = entprop.Acceleration; | ||
766 | _rotationalVelocity = entprop.RotationalVelocity; | ||
767 | |||
768 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. | ||
769 | PositionSanityCheck(true); | ||
770 | |||
771 | if (_velocityMotor.Enabled) | ||
772 | { | ||
773 | // TODO: Decide if the step parameters should be changed depending on the avatar's | ||
774 | // state (flying, colliding, ...). | ||
775 | |||
776 | OMV.Vector3 stepVelocity = _velocityMotor.Step(PhysicsScene.LastTimeStep); | ||
777 | |||
778 | // If falling, we keep the world's downward vector no matter what the other axis specify. | ||
779 | if (!Flying && !IsColliding) | ||
780 | { | ||
781 | stepVelocity.Z = entprop.Velocity.Z; | ||
782 | DetailLog("{0},BSCharacter.UpdateProperties,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||
783 | } | ||
784 | |||
785 | // If the user has said stop and we've stopped applying velocity correction, | ||
786 | // the motor can be turned off. Set the velocity to zero so the zero motion is sent to the viewer. | ||
787 | if (_velocityMotor.TargetValue.ApproxEquals(OMV.Vector3.Zero, 0.01f) && _velocityMotor.ErrorIsZero) | ||
788 | { | ||
789 | ZeroMotion(true); | ||
790 | stepVelocity = OMV.Vector3.Zero; | ||
791 | _velocityMotor.Enabled = false; | ||
792 | DetailLog("{0},BSCharacter.UpdateProperties,taint,disableVelocityMotor,m={1}", LocalID, _velocityMotor); | ||
793 | } | ||
794 | |||
795 | _velocity = stepVelocity; | ||
796 | entprop.Velocity = _velocity; | ||
797 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | ||
798 | } | ||
799 | |||
800 | // remember the current and last set values | ||
801 | LastEntityProperties = CurrentEntityProperties; | ||
802 | CurrentEntityProperties = entprop; | ||
803 | |||
804 | // Tell the linkset about value changes | ||
805 | Linkset.UpdateProperties(this, true); | ||
806 | |||
807 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. | ||
808 | // base.RequestPhysicsterseUpdate(); | ||
809 | |||
810 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
811 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | ||
812 | } | ||
813 | } | ||
814 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs new file mode 100644 index 0000000..f1bed39 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs | |||
@@ -0,0 +1,135 @@ | |||
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.BulletSNPlugin | ||
33 | { | ||
34 | |||
35 | public abstract class BSConstraint : IDisposable | ||
36 | { | ||
37 | private static string LogHeader = "[BULLETSIM CONSTRAINT]"; | ||
38 | |||
39 | protected BulletWorld m_world; | ||
40 | protected BulletBody m_body1; | ||
41 | protected BulletBody m_body2; | ||
42 | protected BulletConstraint m_constraint; | ||
43 | protected bool m_enabled = false; | ||
44 | |||
45 | public BulletBody Body1 { get { return m_body1; } } | ||
46 | public BulletBody Body2 { get { return m_body2; } } | ||
47 | public BulletConstraint Constraint { get { return m_constraint; } } | ||
48 | public abstract ConstraintType Type { get; } | ||
49 | public bool IsEnabled { get { return m_enabled; } } | ||
50 | |||
51 | public BSConstraint() | ||
52 | { | ||
53 | } | ||
54 | |||
55 | public virtual void Dispose() | ||
56 | { | ||
57 | if (m_enabled) | ||
58 | { | ||
59 | m_enabled = false; | ||
60 | if (m_constraint.HasPhysicalConstraint) | ||
61 | { | ||
62 | bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); | ||
63 | m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", | ||
64 | BSScene.DetailLogZero, | ||
65 | m_body1.ID, m_body1.ptr.ToString(), | ||
66 | m_body2.ID, m_body2.ptr.ToString(), | ||
67 | success); | ||
68 | m_constraint.Clear(); | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | |||
73 | public virtual bool SetLinearLimits(Vector3 low, Vector3 high) | ||
74 | { | ||
75 | bool ret = false; | ||
76 | if (m_enabled) | ||
77 | ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | public virtual bool SetAngularLimits(Vector3 low, Vector3 high) | ||
82 | { | ||
83 | bool ret = false; | ||
84 | if (m_enabled) | ||
85 | ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high); | ||
86 | return ret; | ||
87 | } | ||
88 | |||
89 | public virtual bool SetSolverIterations(float cnt) | ||
90 | { | ||
91 | bool ret = false; | ||
92 | if (m_enabled) | ||
93 | { | ||
94 | BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt); | ||
95 | ret = true; | ||
96 | } | ||
97 | return ret; | ||
98 | } | ||
99 | |||
100 | public virtual bool CalculateTransforms() | ||
101 | { | ||
102 | bool ret = false; | ||
103 | if (m_enabled) | ||
104 | { | ||
105 | // Recompute the internal transforms | ||
106 | BulletSimAPI.CalculateTransforms2(m_constraint.ptr); | ||
107 | ret = true; | ||
108 | } | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | // Reset this constraint making sure it has all its internal structures | ||
113 | // recomputed and is enabled and ready to go. | ||
114 | public virtual bool RecomputeConstraintVariables(float mass) | ||
115 | { | ||
116 | bool ret = false; | ||
117 | if (m_enabled) | ||
118 | { | ||
119 | ret = CalculateTransforms(); | ||
120 | if (ret) | ||
121 | { | ||
122 | // Setting an object's mass to zero (making it static like when it's selected) | ||
123 | // automatically disables the constraints. | ||
124 | // If the link is enabled, be sure to set the constraint itself to enabled. | ||
125 | BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, BSParam.NumericBool(true)); | ||
126 | } | ||
127 | else | ||
128 | { | ||
129 | m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID); | ||
130 | } | ||
131 | } | ||
132 | return ret; | ||
133 | } | ||
134 | } | ||
135 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs new file mode 100644 index 0000000..d1e3f55 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs | |||
@@ -0,0 +1,153 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above 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.BulletSNPlugin | ||
33 | { | ||
34 | |||
35 | public sealed 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 | // Create a btGeneric6DofConstraint | ||
42 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
43 | Vector3 frame1, Quaternion frame1rot, | ||
44 | Vector3 frame2, Quaternion frame2rot, | ||
45 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
46 | { | ||
47 | m_world = world; | ||
48 | m_body1 = obj1; | ||
49 | m_body2 = obj2; | ||
50 | m_constraint = new BulletConstraint( | ||
51 | BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr, | ||
52 | frame1, frame1rot, | ||
53 | frame2, frame2rot, | ||
54 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
55 | m_enabled = true; | ||
56 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | ||
57 | BSScene.DetailLogZero, world.worldID, | ||
58 | obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString()); | ||
59 | } | ||
60 | |||
61 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
62 | Vector3 joinPoint, | ||
63 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
64 | { | ||
65 | m_world = world; | ||
66 | m_body1 = obj1; | ||
67 | m_body2 = obj2; | ||
68 | if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody) | ||
69 | { | ||
70 | world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | ||
71 | BSScene.DetailLogZero, world.worldID, | ||
72 | obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString()); | ||
73 | world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | ||
74 | LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString()); | ||
75 | m_enabled = false; | ||
76 | } | ||
77 | else | ||
78 | { | ||
79 | m_constraint = new BulletConstraint( | ||
80 | BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr, | ||
81 | joinPoint, | ||
82 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
83 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", | ||
84 | BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString(), | ||
85 | obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString()); | ||
86 | if (!m_constraint.HasPhysicalConstraint) | ||
87 | { | ||
88 | world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", | ||
89 | LogHeader, obj1.ID, obj2.ID); | ||
90 | m_enabled = false; | ||
91 | } | ||
92 | else | ||
93 | { | ||
94 | m_enabled = true; | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) | ||
100 | { | ||
101 | bool ret = false; | ||
102 | if (m_enabled) | ||
103 | { | ||
104 | BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); | ||
105 | ret = true; | ||
106 | } | ||
107 | return ret; | ||
108 | } | ||
109 | |||
110 | public bool SetCFMAndERP(float cfm, float erp) | ||
111 | { | ||
112 | bool ret = false; | ||
113 | if (m_enabled) | ||
114 | { | ||
115 | BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); | ||
116 | BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); | ||
117 | BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); | ||
118 | ret = true; | ||
119 | } | ||
120 | return ret; | ||
121 | } | ||
122 | |||
123 | public bool UseFrameOffset(bool useOffset) | ||
124 | { | ||
125 | bool ret = false; | ||
126 | float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; | ||
127 | if (m_enabled) | ||
128 | ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff); | ||
129 | return ret; | ||
130 | } | ||
131 | |||
132 | public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce) | ||
133 | { | ||
134 | bool ret = false; | ||
135 | float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; | ||
136 | if (m_enabled) | ||
137 | { | ||
138 | ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce); | ||
139 | m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", | ||
140 | BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); | ||
141 | } | ||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | public bool SetBreakingImpulseThreshold(float threshold) | ||
146 | { | ||
147 | bool ret = false; | ||
148 | if (m_enabled) | ||
149 | ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold); | ||
150 | return ret; | ||
151 | } | ||
152 | } | ||
153 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs new file mode 100644 index 0000000..87d1e44 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.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 log4net; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSNPlugin | ||
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 | RemoveAndDestroyConstraint(constrain); | ||
121 | ret = true; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | // The constraint MUST exist in the collection | ||
129 | public bool RemoveAndDestroyConstraint(BSConstraint constrain) | ||
130 | { | ||
131 | lock (m_constraints) | ||
132 | { | ||
133 | // remove the constraint from our collection | ||
134 | m_constraints.Remove(constrain); | ||
135 | } | ||
136 | // tell the engine that all its structures need to be freed | ||
137 | constrain.Dispose(); | ||
138 | // we destroyed something | ||
139 | return true; | ||
140 | } | ||
141 | |||
142 | // Remove all constraints that reference the passed body. | ||
143 | // Return 'true' if any constraints were destroyed. | ||
144 | public bool RemoveAndDestroyConstraint(BulletBody body1) | ||
145 | { | ||
146 | List<BSConstraint> toRemove = new List<BSConstraint>(); | ||
147 | uint lookingID = body1.ID; | ||
148 | lock (m_constraints) | ||
149 | { | ||
150 | foreach (BSConstraint constrain in m_constraints) | ||
151 | { | ||
152 | if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID) | ||
153 | { | ||
154 | toRemove.Add(constrain); | ||
155 | } | ||
156 | } | ||
157 | foreach (BSConstraint constrain in toRemove) | ||
158 | { | ||
159 | m_constraints.Remove(constrain); | ||
160 | constrain.Dispose(); | ||
161 | } | ||
162 | } | ||
163 | return (toRemove.Count > 0); | ||
164 | } | ||
165 | |||
166 | public bool RecalculateAllConstraints() | ||
167 | { | ||
168 | bool ret = false; | ||
169 | lock (m_constraints) | ||
170 | { | ||
171 | foreach (BSConstraint constrain in m_constraints) | ||
172 | { | ||
173 | constrain.CalculateTransforms(); | ||
174 | ret = true; | ||
175 | } | ||
176 | } | ||
177 | return ret; | ||
178 | } | ||
179 | } | ||
180 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs new file mode 100644 index 0000000..fbd1bc0 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs | |||
@@ -0,0 +1,57 @@ | |||
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.BulletSNPlugin | ||
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 | { | ||
44 | m_world = world; | ||
45 | m_body1 = obj1; | ||
46 | m_body2 = obj2; | ||
47 | m_constraint = new BulletConstraint( | ||
48 | BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr, | ||
49 | pivotInA, pivotInB, | ||
50 | axisInA, axisInB, | ||
51 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
52 | m_enabled = true; | ||
53 | } | ||
54 | |||
55 | } | ||
56 | |||
57 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs new file mode 100644 index 0000000..415ad4f --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs | |||
@@ -0,0 +1,1377 @@ | |||
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.Region.Physics.Manager; | ||
39 | |||
40 | namespace OpenSim.Region.Physics.BulletSNPlugin | ||
41 | { | ||
42 | public sealed class BSDynamics | ||
43 | { | ||
44 | private static string LogHeader = "[BULLETSIM VEHICLE]"; | ||
45 | |||
46 | private BSScene PhysicsScene { get; set; } | ||
47 | // the prim this dynamic controller belongs to | ||
48 | private BSPrim Prim { get; set; } | ||
49 | |||
50 | // mass of the vehicle fetched each time we're calles | ||
51 | private float m_vehicleMass; | ||
52 | |||
53 | // Vehicle properties | ||
54 | public Vehicle Type { get; set; } | ||
55 | |||
56 | // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier | ||
57 | private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: | ||
58 | // HOVER_TERRAIN_ONLY | ||
59 | // HOVER_GLOBAL_HEIGHT | ||
60 | // NO_DEFLECTION_UP | ||
61 | // HOVER_WATER_ONLY | ||
62 | // HOVER_UP_ONLY | ||
63 | // LIMIT_MOTOR_UP | ||
64 | // LIMIT_ROLL_ONLY | ||
65 | private Vector3 m_BlockingEndPoint = Vector3.Zero; | ||
66 | private Quaternion m_RollreferenceFrame = Quaternion.Identity; | ||
67 | private Quaternion m_referenceFrame = Quaternion.Identity; | ||
68 | |||
69 | // Linear properties | ||
70 | private BSVMotor m_linearMotor = new BSVMotor("LinearMotor"); | ||
71 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | ||
72 | private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center | ||
73 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL | ||
74 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | ||
75 | private float m_linearMotorDecayTimescale = 0; | ||
76 | private float m_linearMotorTimescale = 0; | ||
77 | private Vector3 m_lastLinearVelocityVector = Vector3.Zero; | ||
78 | private Vector3 m_lastPositionVector = Vector3.Zero; | ||
79 | // private bool m_LinearMotorSetLastFrame = false; | ||
80 | // private Vector3 m_linearMotorOffset = Vector3.Zero; | ||
81 | |||
82 | //Angular properties | ||
83 | private BSVMotor m_angularMotor = new BSVMotor("AngularMotor"); | ||
84 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | ||
85 | // private int m_angularMotorApply = 0; // application frame counter | ||
86 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity | ||
87 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | ||
88 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | ||
89 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | ||
90 | private Vector3 m_lastAngularVelocity = Vector3.Zero; | ||
91 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body | ||
92 | |||
93 | //Deflection properties | ||
94 | private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection"); | ||
95 | private float m_angularDeflectionEfficiency = 0; | ||
96 | private float m_angularDeflectionTimescale = 0; | ||
97 | private float m_linearDeflectionEfficiency = 0; | ||
98 | private float m_linearDeflectionTimescale = 0; | ||
99 | |||
100 | //Banking properties | ||
101 | private float m_bankingEfficiency = 0; | ||
102 | private float m_bankingMix = 0; | ||
103 | private float m_bankingTimescale = 0; | ||
104 | |||
105 | //Hover and Buoyancy properties | ||
106 | private BSVMotor m_hoverMotor = new BSVMotor("Hover"); | ||
107 | private float m_VhoverHeight = 0f; | ||
108 | private float m_VhoverEfficiency = 0f; | ||
109 | private float m_VhoverTimescale = 0f; | ||
110 | private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height | ||
111 | private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. | ||
112 | // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) | ||
113 | // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. | ||
114 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. | ||
115 | |||
116 | //Attractor properties | ||
117 | private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); | ||
118 | private float m_verticalAttractionEfficiency = 1.0f; // damped | ||
119 | private float m_verticalAttractionCutoff = 500f; // per the documentation | ||
120 | // Timescale > cutoff means no vert attractor. | ||
121 | private float m_verticalAttractionTimescale = 510f; | ||
122 | |||
123 | // Just some recomputed constants: | ||
124 | static readonly float PIOverFour = ((float)Math.PI) / 4f; | ||
125 | static readonly float PIOverTwo = ((float)Math.PI) / 2f; | ||
126 | |||
127 | public BSDynamics(BSScene myScene, BSPrim myPrim) | ||
128 | { | ||
129 | PhysicsScene = myScene; | ||
130 | Prim = myPrim; | ||
131 | Type = Vehicle.TYPE_NONE; | ||
132 | } | ||
133 | |||
134 | // Return 'true' if this vehicle is doing vehicle things | ||
135 | public bool IsActive | ||
136 | { | ||
137 | get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; } | ||
138 | } | ||
139 | |||
140 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | ||
141 | { | ||
142 | VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | ||
143 | switch (pParam) | ||
144 | { | ||
145 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: | ||
146 | m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); | ||
147 | break; | ||
148 | case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: | ||
149 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); | ||
150 | break; | ||
151 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | ||
152 | m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); | ||
153 | m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; | ||
154 | break; | ||
155 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | ||
156 | m_angularMotorTimescale = Math.Max(pValue, 0.01f); | ||
157 | m_angularMotor.TimeScale = m_angularMotorTimescale; | ||
158 | break; | ||
159 | case Vehicle.BANKING_EFFICIENCY: | ||
160 | m_bankingEfficiency = ClampInRange(-1f, pValue, 1f); | ||
161 | break; | ||
162 | case Vehicle.BANKING_MIX: | ||
163 | m_bankingMix = Math.Max(pValue, 0.01f); | ||
164 | break; | ||
165 | case Vehicle.BANKING_TIMESCALE: | ||
166 | m_bankingTimescale = Math.Max(pValue, 0.01f); | ||
167 | break; | ||
168 | case Vehicle.BUOYANCY: | ||
169 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); | ||
170 | break; | ||
171 | case Vehicle.HOVER_EFFICIENCY: | ||
172 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); | ||
173 | break; | ||
174 | case Vehicle.HOVER_HEIGHT: | ||
175 | m_VhoverHeight = pValue; | ||
176 | break; | ||
177 | case Vehicle.HOVER_TIMESCALE: | ||
178 | m_VhoverTimescale = Math.Max(pValue, 0.01f); | ||
179 | break; | ||
180 | case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: | ||
181 | m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); | ||
182 | break; | ||
183 | case Vehicle.LINEAR_DEFLECTION_TIMESCALE: | ||
184 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); | ||
185 | break; | ||
186 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | ||
187 | m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); | ||
188 | m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; | ||
189 | break; | ||
190 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | ||
191 | m_linearMotorTimescale = Math.Max(pValue, 0.01f); | ||
192 | m_linearMotor.TimeScale = m_linearMotorTimescale; | ||
193 | break; | ||
194 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | ||
195 | m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f); | ||
196 | m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; | ||
197 | break; | ||
198 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | ||
199 | m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); | ||
200 | m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale; | ||
201 | break; | ||
202 | |||
203 | // These are vector properties but the engine lets you use a single float value to | ||
204 | // set all of the components to the same value | ||
205 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | ||
206 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | ||
207 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
208 | break; | ||
209 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | ||
210 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | ||
211 | m_angularMotor.SetTarget(m_angularMotorDirection); | ||
212 | break; | ||
213 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | ||
214 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | ||
215 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
216 | break; | ||
217 | case Vehicle.LINEAR_MOTOR_DIRECTION: | ||
218 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | ||
219 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | ||
220 | m_linearMotor.SetTarget(m_linearMotorDirection); | ||
221 | break; | ||
222 | case Vehicle.LINEAR_MOTOR_OFFSET: | ||
223 | m_linearMotorOffset = new Vector3(pValue, pValue, pValue); | ||
224 | break; | ||
225 | |||
226 | } | ||
227 | }//end ProcessFloatVehicleParam | ||
228 | |||
229 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) | ||
230 | { | ||
231 | VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | ||
232 | switch (pParam) | ||
233 | { | ||
234 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | ||
235 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
236 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
237 | break; | ||
238 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | ||
239 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | ||
240 | pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f); | ||
241 | pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); | ||
242 | pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); | ||
243 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
244 | m_angularMotor.SetTarget(m_angularMotorDirection); | ||
245 | break; | ||
246 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | ||
247 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
248 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
249 | break; | ||
250 | case Vehicle.LINEAR_MOTOR_DIRECTION: | ||
251 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
252 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
253 | m_linearMotor.SetTarget(m_linearMotorDirection); | ||
254 | break; | ||
255 | case Vehicle.LINEAR_MOTOR_OFFSET: | ||
256 | m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
257 | break; | ||
258 | case Vehicle.BLOCK_EXIT: | ||
259 | m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
260 | break; | ||
261 | } | ||
262 | }//end ProcessVectorVehicleParam | ||
263 | |||
264 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) | ||
265 | { | ||
266 | VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | ||
267 | switch (pParam) | ||
268 | { | ||
269 | case Vehicle.REFERENCE_FRAME: | ||
270 | m_referenceFrame = pValue; | ||
271 | break; | ||
272 | case Vehicle.ROLL_FRAME: | ||
273 | m_RollreferenceFrame = pValue; | ||
274 | break; | ||
275 | } | ||
276 | }//end ProcessRotationVehicleParam | ||
277 | |||
278 | internal void ProcessVehicleFlags(int pParam, bool remove) | ||
279 | { | ||
280 | VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); | ||
281 | VehicleFlag parm = (VehicleFlag)pParam; | ||
282 | if (pParam == -1) | ||
283 | m_flags = (VehicleFlag)0; | ||
284 | else | ||
285 | { | ||
286 | if (remove) | ||
287 | m_flags &= ~parm; | ||
288 | else | ||
289 | m_flags |= parm; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | internal void ProcessTypeChange(Vehicle pType) | ||
294 | { | ||
295 | VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); | ||
296 | // Set Defaults For Type | ||
297 | Type = pType; | ||
298 | switch (pType) | ||
299 | { | ||
300 | case Vehicle.TYPE_NONE: | ||
301 | m_linearMotorDirection = Vector3.Zero; | ||
302 | m_linearMotorTimescale = 0; | ||
303 | m_linearMotorDecayTimescale = 0; | ||
304 | m_linearFrictionTimescale = new Vector3(0, 0, 0); | ||
305 | |||
306 | m_angularMotorDirection = Vector3.Zero; | ||
307 | m_angularMotorDecayTimescale = 0; | ||
308 | m_angularMotorTimescale = 0; | ||
309 | m_angularFrictionTimescale = new Vector3(0, 0, 0); | ||
310 | |||
311 | m_VhoverHeight = 0; | ||
312 | m_VhoverEfficiency = 0; | ||
313 | m_VhoverTimescale = 0; | ||
314 | m_VehicleBuoyancy = 0; | ||
315 | |||
316 | m_linearDeflectionEfficiency = 1; | ||
317 | m_linearDeflectionTimescale = 1; | ||
318 | |||
319 | m_angularDeflectionEfficiency = 0; | ||
320 | m_angularDeflectionTimescale = 1000; | ||
321 | |||
322 | m_verticalAttractionEfficiency = 0; | ||
323 | m_verticalAttractionTimescale = 0; | ||
324 | |||
325 | m_bankingEfficiency = 0; | ||
326 | m_bankingTimescale = 1000; | ||
327 | m_bankingMix = 1; | ||
328 | |||
329 | m_referenceFrame = Quaternion.Identity; | ||
330 | m_flags = (VehicleFlag)0; | ||
331 | |||
332 | break; | ||
333 | |||
334 | case Vehicle.TYPE_SLED: | ||
335 | m_linearMotorDirection = Vector3.Zero; | ||
336 | m_linearMotorTimescale = 1000; | ||
337 | m_linearMotorDecayTimescale = 120; | ||
338 | m_linearFrictionTimescale = new Vector3(30, 1, 1000); | ||
339 | |||
340 | m_angularMotorDirection = Vector3.Zero; | ||
341 | m_angularMotorTimescale = 1000; | ||
342 | m_angularMotorDecayTimescale = 120; | ||
343 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
344 | |||
345 | m_VhoverHeight = 0; | ||
346 | m_VhoverEfficiency = 10; // TODO: this looks wrong!! | ||
347 | m_VhoverTimescale = 10; | ||
348 | m_VehicleBuoyancy = 0; | ||
349 | |||
350 | m_linearDeflectionEfficiency = 1; | ||
351 | m_linearDeflectionTimescale = 1; | ||
352 | |||
353 | m_angularDeflectionEfficiency = 1; | ||
354 | m_angularDeflectionTimescale = 1000; | ||
355 | |||
356 | m_verticalAttractionEfficiency = 0; | ||
357 | m_verticalAttractionTimescale = 0; | ||
358 | |||
359 | m_bankingEfficiency = 0; | ||
360 | m_bankingTimescale = 10; | ||
361 | m_bankingMix = 1; | ||
362 | |||
363 | m_referenceFrame = Quaternion.Identity; | ||
364 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | ||
365 | | VehicleFlag.HOVER_TERRAIN_ONLY | ||
366 | | VehicleFlag.HOVER_GLOBAL_HEIGHT | ||
367 | | VehicleFlag.HOVER_UP_ONLY); | ||
368 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | ||
369 | | VehicleFlag.LIMIT_ROLL_ONLY | ||
370 | | VehicleFlag.LIMIT_MOTOR_UP); | ||
371 | |||
372 | break; | ||
373 | case Vehicle.TYPE_CAR: | ||
374 | m_linearMotorDirection = Vector3.Zero; | ||
375 | m_linearMotorTimescale = 1; | ||
376 | m_linearMotorDecayTimescale = 60; | ||
377 | m_linearFrictionTimescale = new Vector3(100, 2, 1000); | ||
378 | |||
379 | m_angularMotorDirection = Vector3.Zero; | ||
380 | m_angularMotorTimescale = 1; | ||
381 | m_angularMotorDecayTimescale = 0.8f; | ||
382 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
383 | |||
384 | m_VhoverHeight = 0; | ||
385 | m_VhoverEfficiency = 0; | ||
386 | m_VhoverTimescale = 1000; | ||
387 | m_VehicleBuoyancy = 0; | ||
388 | |||
389 | m_linearDeflectionEfficiency = 1; | ||
390 | m_linearDeflectionTimescale = 2; | ||
391 | |||
392 | m_angularDeflectionEfficiency = 0; | ||
393 | m_angularDeflectionTimescale = 10; | ||
394 | |||
395 | m_verticalAttractionEfficiency = 1f; | ||
396 | m_verticalAttractionTimescale = 10f; | ||
397 | |||
398 | m_bankingEfficiency = -0.2f; | ||
399 | m_bankingMix = 1; | ||
400 | m_bankingTimescale = 1; | ||
401 | |||
402 | m_referenceFrame = Quaternion.Identity; | ||
403 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | ||
404 | | VehicleFlag.HOVER_TERRAIN_ONLY | ||
405 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
406 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | ||
407 | | VehicleFlag.LIMIT_ROLL_ONLY | ||
408 | | VehicleFlag.LIMIT_MOTOR_UP | ||
409 | | VehicleFlag.HOVER_UP_ONLY); | ||
410 | break; | ||
411 | case Vehicle.TYPE_BOAT: | ||
412 | m_linearMotorDirection = Vector3.Zero; | ||
413 | m_linearMotorTimescale = 5; | ||
414 | m_linearMotorDecayTimescale = 60; | ||
415 | m_linearFrictionTimescale = new Vector3(10, 3, 2); | ||
416 | |||
417 | m_angularMotorDirection = Vector3.Zero; | ||
418 | m_angularMotorTimescale = 4; | ||
419 | m_angularMotorDecayTimescale = 4; | ||
420 | m_angularFrictionTimescale = new Vector3(10,10,10); | ||
421 | |||
422 | m_VhoverHeight = 0; | ||
423 | m_VhoverEfficiency = 0.5f; | ||
424 | m_VhoverTimescale = 2; | ||
425 | m_VehicleBuoyancy = 1; | ||
426 | |||
427 | m_linearDeflectionEfficiency = 0.5f; | ||
428 | m_linearDeflectionTimescale = 3; | ||
429 | |||
430 | m_angularDeflectionEfficiency = 0.5f; | ||
431 | m_angularDeflectionTimescale = 5; | ||
432 | |||
433 | m_verticalAttractionEfficiency = 0.5f; | ||
434 | m_verticalAttractionTimescale = 5f; | ||
435 | |||
436 | m_bankingEfficiency = -0.3f; | ||
437 | m_bankingMix = 0.8f; | ||
438 | m_bankingTimescale = 1; | ||
439 | |||
440 | m_referenceFrame = Quaternion.Identity; | ||
441 | m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | ||
442 | | VehicleFlag.HOVER_GLOBAL_HEIGHT | ||
443 | | VehicleFlag.LIMIT_ROLL_ONLY | ||
444 | | VehicleFlag.HOVER_UP_ONLY); | ||
445 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | ||
446 | | VehicleFlag.LIMIT_MOTOR_UP | ||
447 | | VehicleFlag.HOVER_WATER_ONLY); | ||
448 | break; | ||
449 | case Vehicle.TYPE_AIRPLANE: | ||
450 | m_linearMotorDirection = Vector3.Zero; | ||
451 | m_linearMotorTimescale = 2; | ||
452 | m_linearMotorDecayTimescale = 60; | ||
453 | m_linearFrictionTimescale = new Vector3(200, 10, 5); | ||
454 | |||
455 | m_angularMotorDirection = Vector3.Zero; | ||
456 | m_angularMotorTimescale = 4; | ||
457 | m_angularMotorDecayTimescale = 4; | ||
458 | m_angularFrictionTimescale = new Vector3(20, 20, 20); | ||
459 | |||
460 | m_VhoverHeight = 0; | ||
461 | m_VhoverEfficiency = 0.5f; | ||
462 | m_VhoverTimescale = 1000; | ||
463 | m_VehicleBuoyancy = 0; | ||
464 | |||
465 | m_linearDeflectionEfficiency = 0.5f; | ||
466 | m_linearDeflectionTimescale = 3; | ||
467 | |||
468 | m_angularDeflectionEfficiency = 1; | ||
469 | m_angularDeflectionTimescale = 2; | ||
470 | |||
471 | m_verticalAttractionEfficiency = 0.9f; | ||
472 | m_verticalAttractionTimescale = 2f; | ||
473 | |||
474 | m_bankingEfficiency = 1; | ||
475 | m_bankingMix = 0.7f; | ||
476 | m_bankingTimescale = 2; | ||
477 | |||
478 | m_referenceFrame = Quaternion.Identity; | ||
479 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | ||
480 | | VehicleFlag.HOVER_TERRAIN_ONLY | ||
481 | | VehicleFlag.HOVER_GLOBAL_HEIGHT | ||
482 | | VehicleFlag.HOVER_UP_ONLY | ||
483 | | VehicleFlag.NO_DEFLECTION_UP | ||
484 | | VehicleFlag.LIMIT_MOTOR_UP); | ||
485 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); | ||
486 | break; | ||
487 | case Vehicle.TYPE_BALLOON: | ||
488 | m_linearMotorDirection = Vector3.Zero; | ||
489 | m_linearMotorTimescale = 5; | ||
490 | m_linearFrictionTimescale = new Vector3(5, 5, 5); | ||
491 | m_linearMotorDecayTimescale = 60; | ||
492 | |||
493 | m_angularMotorDirection = Vector3.Zero; | ||
494 | m_angularMotorTimescale = 6; | ||
495 | m_angularFrictionTimescale = new Vector3(10, 10, 10); | ||
496 | m_angularMotorDecayTimescale = 10; | ||
497 | |||
498 | m_VhoverHeight = 5; | ||
499 | m_VhoverEfficiency = 0.8f; | ||
500 | m_VhoverTimescale = 10; | ||
501 | m_VehicleBuoyancy = 1; | ||
502 | |||
503 | m_linearDeflectionEfficiency = 0; | ||
504 | m_linearDeflectionTimescale = 5; | ||
505 | |||
506 | m_angularDeflectionEfficiency = 0; | ||
507 | m_angularDeflectionTimescale = 5; | ||
508 | |||
509 | m_verticalAttractionEfficiency = 1f; | ||
510 | m_verticalAttractionTimescale = 100f; | ||
511 | |||
512 | m_bankingEfficiency = 0; | ||
513 | m_bankingMix = 0.7f; | ||
514 | m_bankingTimescale = 5; | ||
515 | |||
516 | m_referenceFrame = Quaternion.Identity; | ||
517 | |||
518 | m_referenceFrame = Quaternion.Identity; | ||
519 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | ||
520 | | VehicleFlag.HOVER_TERRAIN_ONLY | ||
521 | | VehicleFlag.HOVER_UP_ONLY | ||
522 | | VehicleFlag.NO_DEFLECTION_UP | ||
523 | | VehicleFlag.LIMIT_MOTOR_UP); | ||
524 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | ||
525 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
526 | break; | ||
527 | } | ||
528 | |||
529 | // Update any physical parameters based on this type. | ||
530 | Refresh(); | ||
531 | |||
532 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, | ||
533 | m_linearMotorDecayTimescale, m_linearFrictionTimescale, | ||
534 | 1f); | ||
535 | m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
536 | |||
537 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, | ||
538 | m_angularMotorDecayTimescale, m_angularFrictionTimescale, | ||
539 | 1f); | ||
540 | m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
541 | |||
542 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, | ||
543 | BSMotor.Infinite, BSMotor.InfiniteVector, | ||
544 | m_verticalAttractionEfficiency); | ||
545 | // Z goes away and we keep X and Y | ||
546 | m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f); | ||
547 | m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
548 | } | ||
549 | |||
550 | // Some of the properties of this prim may have changed. | ||
551 | // Do any updating needed for a vehicle | ||
552 | public void Refresh() | ||
553 | { | ||
554 | if (IsActive) | ||
555 | { | ||
556 | // Remember the mass so we don't have to fetch it every step | ||
557 | m_vehicleMass = Prim.Linkset.LinksetMass; | ||
558 | |||
559 | // Friction affects are handled by this vehicle code | ||
560 | float friction = 0f; | ||
561 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction); | ||
562 | |||
563 | // Moderate angular movement introduced by Bullet. | ||
564 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. | ||
565 | // Maybe compute linear and angular factor and damping from params. | ||
566 | float angularDamping = BSParam.VehicleAngularDamping; | ||
567 | BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); | ||
568 | |||
569 | // Vehicles report collision events so we know when it's on the ground | ||
570 | BulletSimAPI.AddToCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
571 | |||
572 | Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass); | ||
573 | BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); | ||
574 | BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr); | ||
575 | |||
576 | Vector3 grav = PhysicsScene.DefaultGravity * (1f - Prim.Buoyancy); | ||
577 | BulletSimAPI.SetGravity2(Prim.PhysBody.ptr, grav); | ||
578 | |||
579 | VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}", | ||
580 | Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping); | ||
581 | } | ||
582 | else | ||
583 | { | ||
584 | BulletSimAPI.RemoveFromCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
585 | } | ||
586 | } | ||
587 | |||
588 | public bool RemoveBodyDependencies(BSPhysObject prim) | ||
589 | { | ||
590 | // If active, we need to add our properties back when the body is rebuilt. | ||
591 | return IsActive; | ||
592 | } | ||
593 | |||
594 | public void RestoreBodyDependencies(BSPhysObject prim) | ||
595 | { | ||
596 | if (Prim.LocalID != prim.LocalID) | ||
597 | { | ||
598 | // The call should be on us by our prim. Error if not. | ||
599 | PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}", | ||
600 | LogHeader, prim.LocalID, Prim.LocalID); | ||
601 | return; | ||
602 | } | ||
603 | Refresh(); | ||
604 | } | ||
605 | |||
606 | #region Known vehicle value functions | ||
607 | // Vehicle physical parameters that we buffer from constant getting and setting. | ||
608 | // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set. | ||
609 | // Changing is remembered and the parameter is stored back into the physics engine only if updated. | ||
610 | // This does two things: 1) saves continuious calls into unmanaged code, and | ||
611 | // 2) signals when a physics property update must happen back to the simulator | ||
612 | // to update values modified for the vehicle. | ||
613 | private int m_knownChanged; | ||
614 | private int m_knownHas; | ||
615 | private float m_knownTerrainHeight; | ||
616 | private float m_knownWaterLevel; | ||
617 | private Vector3 m_knownPosition; | ||
618 | private Vector3 m_knownVelocity; | ||
619 | private Vector3 m_knownForce; | ||
620 | private Quaternion m_knownOrientation; | ||
621 | private Vector3 m_knownRotationalVelocity; | ||
622 | private Vector3 m_knownRotationalForce; | ||
623 | private Vector3 m_knownForwardVelocity; // vehicle relative forward speed | ||
624 | |||
625 | private const int m_knownChangedPosition = 1 << 0; | ||
626 | private const int m_knownChangedVelocity = 1 << 1; | ||
627 | private const int m_knownChangedForce = 1 << 2; | ||
628 | private const int m_knownChangedOrientation = 1 << 3; | ||
629 | private const int m_knownChangedRotationalVelocity = 1 << 4; | ||
630 | private const int m_knownChangedRotationalForce = 1 << 5; | ||
631 | private const int m_knownChangedTerrainHeight = 1 << 6; | ||
632 | private const int m_knownChangedWaterLevel = 1 << 7; | ||
633 | private const int m_knownChangedForwardVelocity = 1 << 8; | ||
634 | |||
635 | private void ForgetKnownVehicleProperties() | ||
636 | { | ||
637 | m_knownHas = 0; | ||
638 | m_knownChanged = 0; | ||
639 | } | ||
640 | // Push all the changed values back into the physics engine | ||
641 | private void PushKnownChanged() | ||
642 | { | ||
643 | if (m_knownChanged != 0) | ||
644 | { | ||
645 | if ((m_knownChanged & m_knownChangedPosition) != 0) | ||
646 | Prim.ForcePosition = m_knownPosition; | ||
647 | |||
648 | if ((m_knownChanged & m_knownChangedOrientation) != 0) | ||
649 | Prim.ForceOrientation = m_knownOrientation; | ||
650 | |||
651 | if ((m_knownChanged & m_knownChangedVelocity) != 0) | ||
652 | { | ||
653 | Prim.ForceVelocity = m_knownVelocity; | ||
654 | BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity); | ||
655 | } | ||
656 | |||
657 | if ((m_knownChanged & m_knownChangedForce) != 0) | ||
658 | Prim.AddForce((Vector3)m_knownForce, false, true); | ||
659 | |||
660 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) | ||
661 | { | ||
662 | Prim.ForceRotationalVelocity = m_knownRotationalVelocity; | ||
663 | // Fake out Bullet by making it think the velocity is the same as last time. | ||
664 | BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, m_knownRotationalVelocity); | ||
665 | } | ||
666 | |||
667 | if ((m_knownChanged & m_knownChangedRotationalForce) != 0) | ||
668 | Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true); | ||
669 | |||
670 | // If we set one of the values (ie, the physics engine didn't do it) we must force | ||
671 | // an UpdateProperties event to send the changes up to the simulator. | ||
672 | BulletSimAPI.PushUpdate2(Prim.PhysBody.ptr); | ||
673 | } | ||
674 | m_knownChanged = 0; | ||
675 | } | ||
676 | |||
677 | // Since the computation of terrain height can be a little involved, this routine | ||
678 | // is used to fetch the height only once for each vehicle simulation step. | ||
679 | private float GetTerrainHeight(Vector3 pos) | ||
680 | { | ||
681 | if ((m_knownHas & m_knownChangedTerrainHeight) == 0) | ||
682 | { | ||
683 | m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | ||
684 | m_knownHas |= m_knownChangedTerrainHeight; | ||
685 | } | ||
686 | return m_knownTerrainHeight; | ||
687 | } | ||
688 | |||
689 | // Since the computation of water level can be a little involved, this routine | ||
690 | // is used ot fetch the level only once for each vehicle simulation step. | ||
691 | private float GetWaterLevel(Vector3 pos) | ||
692 | { | ||
693 | if ((m_knownHas & m_knownChangedWaterLevel) == 0) | ||
694 | { | ||
695 | m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); | ||
696 | m_knownHas |= m_knownChangedWaterLevel; | ||
697 | } | ||
698 | return (float)m_knownWaterLevel; | ||
699 | } | ||
700 | |||
701 | private Vector3 VehiclePosition | ||
702 | { | ||
703 | get | ||
704 | { | ||
705 | if ((m_knownHas & m_knownChangedPosition) == 0) | ||
706 | { | ||
707 | m_knownPosition = Prim.ForcePosition; | ||
708 | m_knownHas |= m_knownChangedPosition; | ||
709 | } | ||
710 | return m_knownPosition; | ||
711 | } | ||
712 | set | ||
713 | { | ||
714 | m_knownPosition = value; | ||
715 | m_knownChanged |= m_knownChangedPosition; | ||
716 | m_knownHas |= m_knownChangedPosition; | ||
717 | } | ||
718 | } | ||
719 | |||
720 | private Quaternion VehicleOrientation | ||
721 | { | ||
722 | get | ||
723 | { | ||
724 | if ((m_knownHas & m_knownChangedOrientation) == 0) | ||
725 | { | ||
726 | m_knownOrientation = Prim.ForceOrientation; | ||
727 | m_knownHas |= m_knownChangedOrientation; | ||
728 | } | ||
729 | return m_knownOrientation; | ||
730 | } | ||
731 | set | ||
732 | { | ||
733 | m_knownOrientation = value; | ||
734 | m_knownChanged |= m_knownChangedOrientation; | ||
735 | m_knownHas |= m_knownChangedOrientation; | ||
736 | } | ||
737 | } | ||
738 | |||
739 | private Vector3 VehicleVelocity | ||
740 | { | ||
741 | get | ||
742 | { | ||
743 | if ((m_knownHas & m_knownChangedVelocity) == 0) | ||
744 | { | ||
745 | m_knownVelocity = Prim.ForceVelocity; | ||
746 | m_knownHas |= m_knownChangedVelocity; | ||
747 | } | ||
748 | return (Vector3)m_knownVelocity; | ||
749 | } | ||
750 | set | ||
751 | { | ||
752 | m_knownVelocity = value; | ||
753 | m_knownChanged |= m_knownChangedVelocity; | ||
754 | m_knownHas |= m_knownChangedVelocity; | ||
755 | } | ||
756 | } | ||
757 | |||
758 | private void VehicleAddForce(Vector3 aForce) | ||
759 | { | ||
760 | if ((m_knownHas & m_knownChangedForce) == 0) | ||
761 | { | ||
762 | m_knownForce = Vector3.Zero; | ||
763 | } | ||
764 | m_knownForce += aForce; | ||
765 | m_knownChanged |= m_knownChangedForce; | ||
766 | m_knownHas |= m_knownChangedForce; | ||
767 | } | ||
768 | |||
769 | private Vector3 VehicleRotationalVelocity | ||
770 | { | ||
771 | get | ||
772 | { | ||
773 | if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) | ||
774 | { | ||
775 | m_knownRotationalVelocity = Prim.ForceRotationalVelocity; | ||
776 | m_knownHas |= m_knownChangedRotationalVelocity; | ||
777 | } | ||
778 | return (Vector3)m_knownRotationalVelocity; | ||
779 | } | ||
780 | set | ||
781 | { | ||
782 | m_knownRotationalVelocity = value; | ||
783 | m_knownChanged |= m_knownChangedRotationalVelocity; | ||
784 | m_knownHas |= m_knownChangedRotationalVelocity; | ||
785 | } | ||
786 | } | ||
787 | private void VehicleAddAngularForce(Vector3 aForce) | ||
788 | { | ||
789 | if ((m_knownHas & m_knownChangedRotationalForce) == 0) | ||
790 | { | ||
791 | m_knownRotationalForce = Vector3.Zero; | ||
792 | } | ||
793 | m_knownRotationalForce += aForce; | ||
794 | m_knownChanged |= m_knownChangedRotationalForce; | ||
795 | m_knownHas |= m_knownChangedRotationalForce; | ||
796 | } | ||
797 | // Vehicle relative forward velocity | ||
798 | private Vector3 VehicleForwardVelocity | ||
799 | { | ||
800 | get | ||
801 | { | ||
802 | if ((m_knownHas & m_knownChangedForwardVelocity) == 0) | ||
803 | { | ||
804 | m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); | ||
805 | m_knownHas |= m_knownChangedForwardVelocity; | ||
806 | } | ||
807 | return m_knownForwardVelocity; | ||
808 | } | ||
809 | } | ||
810 | private float VehicleForwardSpeed | ||
811 | { | ||
812 | get | ||
813 | { | ||
814 | return VehicleForwardVelocity.X; | ||
815 | } | ||
816 | } | ||
817 | |||
818 | #endregion // Known vehicle value functions | ||
819 | |||
820 | // One step of the vehicle properties for the next 'pTimestep' seconds. | ||
821 | internal void Step(float pTimestep) | ||
822 | { | ||
823 | if (!IsActive) return; | ||
824 | |||
825 | ForgetKnownVehicleProperties(); | ||
826 | |||
827 | MoveLinear(pTimestep); | ||
828 | MoveAngular(pTimestep); | ||
829 | |||
830 | LimitRotation(pTimestep); | ||
831 | |||
832 | // remember the position so next step we can limit absolute movement effects | ||
833 | m_lastPositionVector = VehiclePosition; | ||
834 | |||
835 | // If we forced the changing of some vehicle parameters, update the values and | ||
836 | // for the physics engine to note the changes so an UpdateProperties event will happen. | ||
837 | PushKnownChanged(); | ||
838 | |||
839 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", | ||
840 | Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity); | ||
841 | } | ||
842 | |||
843 | // Apply the effect of the linear motor and other linear motions (like hover and float). | ||
844 | private void MoveLinear(float pTimestep) | ||
845 | { | ||
846 | Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); | ||
847 | |||
848 | // The movement computed in the linear motor is relative to the vehicle | ||
849 | // coordinates. Rotate the movement to world coordinates. | ||
850 | linearMotorContribution *= VehicleOrientation; | ||
851 | |||
852 | // ================================================================== | ||
853 | // Buoyancy: force to overcome gravity. | ||
854 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | ||
855 | // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity. | ||
856 | Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy; | ||
857 | |||
858 | Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep); | ||
859 | |||
860 | Vector3 hoverContribution = ComputeLinearHover(pTimestep); | ||
861 | |||
862 | ComputeLinearBlockingEndPoint(pTimestep); | ||
863 | |||
864 | Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep); | ||
865 | |||
866 | // ================================================================== | ||
867 | Vector3 newVelocity = linearMotorContribution | ||
868 | + terrainHeightContribution | ||
869 | + hoverContribution | ||
870 | + limitMotorUpContribution; | ||
871 | |||
872 | Vector3 newForce = buoyancyContribution; | ||
873 | |||
874 | // If not changing some axis, reduce out velocity | ||
875 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | ||
876 | newVelocity.X = 0; | ||
877 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | ||
878 | newVelocity.Y = 0; | ||
879 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
880 | newVelocity.Z = 0; | ||
881 | |||
882 | // ================================================================== | ||
883 | // Clamp high or low velocities | ||
884 | float newVelocityLengthSq = newVelocity.LengthSquared(); | ||
885 | if (newVelocityLengthSq > 1000f) | ||
886 | { | ||
887 | newVelocity /= newVelocity.Length(); | ||
888 | newVelocity *= 1000f; | ||
889 | } | ||
890 | else if (newVelocityLengthSq < 0.001f) | ||
891 | newVelocity = Vector3.Zero; | ||
892 | |||
893 | // ================================================================== | ||
894 | // Stuff new linear velocity into the vehicle. | ||
895 | // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us. | ||
896 | VehicleVelocity = newVelocity; | ||
897 | |||
898 | // Other linear forces are applied as forces. | ||
899 | Vector3 totalDownForce = newForce * m_vehicleMass; | ||
900 | if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f)) | ||
901 | { | ||
902 | VehicleAddForce(totalDownForce); | ||
903 | } | ||
904 | |||
905 | VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}", | ||
906 | Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding); | ||
907 | VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}", | ||
908 | Prim.LocalID, | ||
909 | linearMotorContribution, terrainHeightContribution, hoverContribution, | ||
910 | limitMotorUpContribution, buoyancyContribution | ||
911 | ); | ||
912 | |||
913 | } // end MoveLinear() | ||
914 | |||
915 | public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep) | ||
916 | { | ||
917 | Vector3 ret = Vector3.Zero; | ||
918 | // If below the terrain, move us above the ground a little. | ||
919 | // TODO: Consider taking the rotated size of the object or possibly casting a ray. | ||
920 | if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) | ||
921 | { | ||
922 | // TODO: correct position by applying force rather than forcing position. | ||
923 | Vector3 newPosition = VehiclePosition; | ||
924 | newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; | ||
925 | VehiclePosition = newPosition; | ||
926 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", | ||
927 | Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); | ||
928 | } | ||
929 | return ret; | ||
930 | } | ||
931 | |||
932 | public Vector3 ComputeLinearHover(float pTimestep) | ||
933 | { | ||
934 | Vector3 ret = Vector3.Zero; | ||
935 | |||
936 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped | ||
937 | // m_VhoverTimescale: time to achieve height | ||
938 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | ||
939 | { | ||
940 | // We should hover, get the target height | ||
941 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) | ||
942 | { | ||
943 | m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight; | ||
944 | } | ||
945 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) | ||
946 | { | ||
947 | m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight; | ||
948 | } | ||
949 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) | ||
950 | { | ||
951 | m_VhoverTargetHeight = m_VhoverHeight; | ||
952 | } | ||
953 | |||
954 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) | ||
955 | { | ||
956 | // If body is already heigher, use its height as target height | ||
957 | if (VehiclePosition.Z > m_VhoverTargetHeight) | ||
958 | m_VhoverTargetHeight = VehiclePosition.Z; | ||
959 | } | ||
960 | |||
961 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | ||
962 | { | ||
963 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) | ||
964 | { | ||
965 | Vector3 pos = VehiclePosition; | ||
966 | pos.Z = m_VhoverTargetHeight; | ||
967 | VehiclePosition = pos; | ||
968 | } | ||
969 | } | ||
970 | else | ||
971 | { | ||
972 | // Error is positive if below the target and negative if above. | ||
973 | float verticalError = m_VhoverTargetHeight - VehiclePosition.Z; | ||
974 | float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; | ||
975 | |||
976 | // TODO: implement m_VhoverEfficiency correctly | ||
977 | if (Math.Abs(verticalError) > m_VhoverEfficiency) | ||
978 | { | ||
979 | ret = new Vector3(0f, 0f, verticalCorrectionVelocity); | ||
980 | } | ||
981 | } | ||
982 | |||
983 | VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}", | ||
984 | Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight); | ||
985 | } | ||
986 | |||
987 | return ret; | ||
988 | } | ||
989 | |||
990 | public bool ComputeLinearBlockingEndPoint(float pTimestep) | ||
991 | { | ||
992 | bool changed = false; | ||
993 | |||
994 | Vector3 pos = VehiclePosition; | ||
995 | Vector3 posChange = pos - m_lastPositionVector; | ||
996 | if (m_BlockingEndPoint != Vector3.Zero) | ||
997 | { | ||
998 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) | ||
999 | { | ||
1000 | pos.X -= posChange.X + 1; | ||
1001 | changed = true; | ||
1002 | } | ||
1003 | if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) | ||
1004 | { | ||
1005 | pos.Y -= posChange.Y + 1; | ||
1006 | changed = true; | ||
1007 | } | ||
1008 | if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) | ||
1009 | { | ||
1010 | pos.Z -= posChange.Z + 1; | ||
1011 | changed = true; | ||
1012 | } | ||
1013 | if (pos.X <= 0) | ||
1014 | { | ||
1015 | pos.X += posChange.X + 1; | ||
1016 | changed = true; | ||
1017 | } | ||
1018 | if (pos.Y <= 0) | ||
1019 | { | ||
1020 | pos.Y += posChange.Y + 1; | ||
1021 | changed = true; | ||
1022 | } | ||
1023 | if (changed) | ||
1024 | { | ||
1025 | VehiclePosition = pos; | ||
1026 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | ||
1027 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); | ||
1028 | } | ||
1029 | } | ||
1030 | return changed; | ||
1031 | } | ||
1032 | |||
1033 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : | ||
1034 | // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when | ||
1035 | // used with conjunction with banking: the strength of the banking will decay when the | ||
1036 | // vehicle no longer experiences collisions. The decay timescale is the same as | ||
1037 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering | ||
1038 | // when they are in mid jump. | ||
1039 | // TODO: this code is wrong. Also, what should it do for boats (height from water)? | ||
1040 | // This is just using the ground and a general collision check. Should really be using | ||
1041 | // a downward raycast to find what is below. | ||
1042 | public Vector3 ComputeLinearMotorUp(float pTimestep) | ||
1043 | { | ||
1044 | Vector3 ret = Vector3.Zero; | ||
1045 | float distanceAboveGround = 0f; | ||
1046 | |||
1047 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) | ||
1048 | { | ||
1049 | float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); | ||
1050 | distanceAboveGround = VehiclePosition.Z - targetHeight; | ||
1051 | // Not colliding if the vehicle is off the ground | ||
1052 | if (!Prim.IsColliding) | ||
1053 | { | ||
1054 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); | ||
1055 | ret = new Vector3(0, 0, -distanceAboveGround); | ||
1056 | } | ||
1057 | // TODO: this calculation is wrong. From the description at | ||
1058 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce | ||
1059 | // has a decay factor. This says this force should | ||
1060 | // be computed with a motor. | ||
1061 | // TODO: add interaction with banking. | ||
1062 | } | ||
1063 | VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", | ||
1064 | Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); | ||
1065 | return ret; | ||
1066 | } | ||
1067 | |||
1068 | // ======================================================================= | ||
1069 | // ======================================================================= | ||
1070 | // Apply the effect of the angular motor. | ||
1071 | // The 'contribution' is how much angular correction velocity each function wants. | ||
1072 | // All the contributions are added together and the resulting velocity is | ||
1073 | // set directly on the vehicle. | ||
1074 | private void MoveAngular(float pTimestep) | ||
1075 | { | ||
1076 | // The user wants this many radians per second angular change? | ||
1077 | Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); | ||
1078 | |||
1079 | // ================================================================== | ||
1080 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : | ||
1081 | // This flag prevents linear deflection parallel to world z-axis. This is useful | ||
1082 | // for preventing ground vehicles with large linear deflection, like bumper cars, | ||
1083 | // from climbing their linear deflection into the sky. | ||
1084 | // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement | ||
1085 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | ||
1086 | { | ||
1087 | angularMotorContribution.X = 0f; | ||
1088 | angularMotorContribution.Y = 0f; | ||
1089 | VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution); | ||
1090 | } | ||
1091 | |||
1092 | Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(); | ||
1093 | |||
1094 | Vector3 deflectionContribution = ComputeAngularDeflection(); | ||
1095 | |||
1096 | Vector3 bankingContribution = ComputeAngularBanking(); | ||
1097 | |||
1098 | // ================================================================== | ||
1099 | m_lastVertAttractor = verticalAttractionContribution; | ||
1100 | |||
1101 | m_lastAngularVelocity = angularMotorContribution | ||
1102 | + verticalAttractionContribution | ||
1103 | + deflectionContribution | ||
1104 | + bankingContribution; | ||
1105 | |||
1106 | // ================================================================== | ||
1107 | // Apply the correction velocity. | ||
1108 | // TODO: Should this be applied as an angular force (torque)? | ||
1109 | if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | ||
1110 | { | ||
1111 | VehicleRotationalVelocity = m_lastAngularVelocity; | ||
1112 | |||
1113 | VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}", | ||
1114 | Prim.LocalID, | ||
1115 | angularMotorContribution, verticalAttractionContribution, | ||
1116 | bankingContribution, deflectionContribution, | ||
1117 | m_lastAngularVelocity | ||
1118 | ); | ||
1119 | } | ||
1120 | else | ||
1121 | { | ||
1122 | // The vehicle is not adding anything angular wise. | ||
1123 | VehicleRotationalVelocity = Vector3.Zero; | ||
1124 | VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); | ||
1125 | } | ||
1126 | |||
1127 | // ================================================================== | ||
1128 | //Offset section | ||
1129 | if (m_linearMotorOffset != Vector3.Zero) | ||
1130 | { | ||
1131 | //Offset of linear velocity doesn't change the linear velocity, | ||
1132 | // but causes a torque to be applied, for example... | ||
1133 | // | ||
1134 | // IIIII >>> IIIII | ||
1135 | // IIIII >>> IIIII | ||
1136 | // IIIII >>> IIIII | ||
1137 | // ^ | ||
1138 | // | Applying a force at the arrow will cause the object to move forward, but also rotate | ||
1139 | // | ||
1140 | // | ||
1141 | // The torque created is the linear velocity crossed with the offset | ||
1142 | |||
1143 | // TODO: this computation should be in the linear section | ||
1144 | // because that is where we know the impulse being applied. | ||
1145 | Vector3 torqueFromOffset = Vector3.Zero; | ||
1146 | // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); | ||
1147 | if (float.IsNaN(torqueFromOffset.X)) | ||
1148 | torqueFromOffset.X = 0; | ||
1149 | if (float.IsNaN(torqueFromOffset.Y)) | ||
1150 | torqueFromOffset.Y = 0; | ||
1151 | if (float.IsNaN(torqueFromOffset.Z)) | ||
1152 | torqueFromOffset.Z = 0; | ||
1153 | |||
1154 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); | ||
1155 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); | ||
1156 | } | ||
1157 | |||
1158 | } | ||
1159 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | ||
1160 | // Some vehicles, like boats, should always keep their up-side up. This can be done by | ||
1161 | // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to | ||
1162 | // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the | ||
1163 | // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency, | ||
1164 | // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An | ||
1165 | // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an | ||
1166 | // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. | ||
1167 | public Vector3 ComputeAngularVerticalAttraction() | ||
1168 | { | ||
1169 | Vector3 ret = Vector3.Zero; | ||
1170 | |||
1171 | // If vertical attaction timescale is reasonable | ||
1172 | if (m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
1173 | { | ||
1174 | // Take a vector pointing up and convert it from world to vehicle relative coords. | ||
1175 | Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; | ||
1176 | |||
1177 | // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) | ||
1178 | // is now: | ||
1179 | // leaning to one side: rotated around the X axis with the Y value going | ||
1180 | // from zero (nearly straight up) to one (completely to the side)) or | ||
1181 | // leaning front-to-back: rotated around the Y axis with the value of X being between | ||
1182 | // zero and one. | ||
1183 | // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. | ||
1184 | |||
1185 | // Y error means needed rotation around X axis and visa versa. | ||
1186 | // Since the error goes from zero to one, the asin is the corresponding angle. | ||
1187 | ret.X = (float)Math.Asin(verticalError.Y); | ||
1188 | // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) | ||
1189 | ret.Y = -(float)Math.Asin(verticalError.X); | ||
1190 | |||
1191 | // If verticalError.Z is negative, the vehicle is upside down. Add additional push. | ||
1192 | if (verticalError.Z < 0f) | ||
1193 | { | ||
1194 | ret.X += PIOverFour; | ||
1195 | ret.Y += PIOverFour; | ||
1196 | } | ||
1197 | |||
1198 | // 'ret' is now the necessary velocity to correct tilt in one second. | ||
1199 | // Correction happens over a number of seconds. | ||
1200 | Vector3 unscaledContrib = ret; | ||
1201 | ret /= m_verticalAttractionTimescale; | ||
1202 | |||
1203 | VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}", | ||
1204 | Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret); | ||
1205 | } | ||
1206 | return ret; | ||
1207 | } | ||
1208 | |||
1209 | // Return the angular correction to correct the direction the vehicle is pointing to be | ||
1210 | // the direction is should want to be pointing. | ||
1211 | // The vehicle is moving in some direction and correct its orientation to it is pointing | ||
1212 | // in that direction. | ||
1213 | // TODO: implement reference frame. | ||
1214 | public Vector3 ComputeAngularDeflection() | ||
1215 | { | ||
1216 | Vector3 ret = Vector3.Zero; | ||
1217 | return ret; // DEBUG DEBUG DEBUG | ||
1218 | // Disable angular deflection for the moment. | ||
1219 | // Since angularMotorUp and angularDeflection are computed independently, they will calculate | ||
1220 | // approximately the same X or Y correction. When added together (when contributions are combined) | ||
1221 | // this creates an over-correction and then wabbling as the target is overshot. | ||
1222 | // TODO: rethink how the different correction computations inter-relate. | ||
1223 | |||
1224 | if (m_angularDeflectionEfficiency != 0) | ||
1225 | { | ||
1226 | // The direction the vehicle is moving | ||
1227 | Vector3 movingDirection = VehicleVelocity; | ||
1228 | movingDirection.Normalize(); | ||
1229 | |||
1230 | // The direction the vehicle is pointing | ||
1231 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; | ||
1232 | pointingDirection.Normalize(); | ||
1233 | |||
1234 | // The difference between what is and what should be. | ||
1235 | Vector3 deflectionError = movingDirection - pointingDirection; | ||
1236 | |||
1237 | // Don't try to correct very large errors (not our job) | ||
1238 | if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f; | ||
1239 | if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f; | ||
1240 | if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f; | ||
1241 | |||
1242 | // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); | ||
1243 | |||
1244 | // Scale the correction by recovery timescale and efficiency | ||
1245 | ret = (-deflectionError) * m_angularDeflectionEfficiency; | ||
1246 | ret /= m_angularDeflectionTimescale; | ||
1247 | |||
1248 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", | ||
1249 | Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret); | ||
1250 | VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", | ||
1251 | Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); | ||
1252 | } | ||
1253 | return ret; | ||
1254 | } | ||
1255 | |||
1256 | // Return an angular change to rotate the vehicle around the Z axis when the vehicle | ||
1257 | // is tipped around the X axis. | ||
1258 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | ||
1259 | // The vertical attractor feature must be enabled in order for the banking behavior to | ||
1260 | // function. The way banking works is this: a rotation around the vehicle's roll-axis will | ||
1261 | // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude | ||
1262 | // of the yaw effect will be proportional to the | ||
1263 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's | ||
1264 | // velocity along its preferred axis of motion. | ||
1265 | // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any | ||
1266 | // positive rotation (by the right-hand rule) about the roll-axis will effect a | ||
1267 | // (negative) torque around the yaw-axis, making it turn to the right--that is the | ||
1268 | // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. | ||
1269 | // Negating the banking coefficient will make it so that the vehicle leans to the | ||
1270 | // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). | ||
1271 | // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making | ||
1272 | // banking vehicles do what you want rather than what the laws of physics allow. | ||
1273 | // For example, consider a real motorcycle...it must be moving forward in order for | ||
1274 | // it to turn while banking, however video-game motorcycles are often configured | ||
1275 | // to turn in place when at a dead stop--because they are often easier to control | ||
1276 | // that way using the limited interface of the keyboard or game controller. The | ||
1277 | // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic | ||
1278 | // banking by functioning as a slider between a banking that is correspondingly | ||
1279 | // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the | ||
1280 | // banking effect depends only on the vehicle's rotation about its roll-axis compared | ||
1281 | // to "dynamic" where the banking is also proportional to its velocity along its | ||
1282 | // roll-axis. Finding the best value of the "mixture" will probably require trial and error. | ||
1283 | // The time it takes for the banking behavior to defeat a preexisting angular velocity about the | ||
1284 | // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to | ||
1285 | // bank quickly then give it a banking timescale of about a second or less, otherwise you can | ||
1286 | // make a sluggish vehicle by giving it a timescale of several seconds. | ||
1287 | public Vector3 ComputeAngularBanking() | ||
1288 | { | ||
1289 | Vector3 ret = Vector3.Zero; | ||
1290 | |||
1291 | if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
1292 | { | ||
1293 | // This works by rotating a unit vector to the orientation of the vehicle. The | ||
1294 | // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt | ||
1295 | // up to one for full over). | ||
1296 | Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation; | ||
1297 | |||
1298 | // Figure out the yaw value for this much roll. | ||
1299 | float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency; | ||
1300 | // Keep the sign | ||
1301 | if (rollComponents.Y < 0f) | ||
1302 | turnComponent = -turnComponent; | ||
1303 | |||
1304 | // TODO: there must be a better computation of the banking force. | ||
1305 | float bankingTurnForce = turnComponent; | ||
1306 | |||
1307 | // actual error = static turn error + dynamic turn error | ||
1308 | float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed; | ||
1309 | // TODO: the banking effect should not go to infinity but what to limit it to? | ||
1310 | mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f); | ||
1311 | |||
1312 | // Build the force vector to change rotation from what it is to what it should be | ||
1313 | ret.Z = -mixedBankingError; | ||
1314 | |||
1315 | // Don't do it all at once. | ||
1316 | ret /= m_bankingTimescale; | ||
1317 | |||
1318 | VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}", | ||
1319 | Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret); | ||
1320 | } | ||
1321 | return ret; | ||
1322 | } | ||
1323 | |||
1324 | // This is from previous instantiations of XXXDynamics.cs. | ||
1325 | // Applies roll reference frame. | ||
1326 | // TODO: is this the right way to separate the code to do this operation? | ||
1327 | // Should this be in MoveAngular()? | ||
1328 | internal void LimitRotation(float timestep) | ||
1329 | { | ||
1330 | Quaternion rotq = VehicleOrientation; | ||
1331 | Quaternion m_rot = rotq; | ||
1332 | if (m_RollreferenceFrame != Quaternion.Identity) | ||
1333 | { | ||
1334 | if (rotq.X >= m_RollreferenceFrame.X) | ||
1335 | { | ||
1336 | m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); | ||
1337 | } | ||
1338 | if (rotq.Y >= m_RollreferenceFrame.Y) | ||
1339 | { | ||
1340 | m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); | ||
1341 | } | ||
1342 | if (rotq.X <= -m_RollreferenceFrame.X) | ||
1343 | { | ||
1344 | m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); | ||
1345 | } | ||
1346 | if (rotq.Y <= -m_RollreferenceFrame.Y) | ||
1347 | { | ||
1348 | m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); | ||
1349 | } | ||
1350 | } | ||
1351 | if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) | ||
1352 | { | ||
1353 | m_rot.X = 0; | ||
1354 | m_rot.Y = 0; | ||
1355 | } | ||
1356 | if (rotq != m_rot) | ||
1357 | { | ||
1358 | VehicleOrientation = m_rot; | ||
1359 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); | ||
1360 | } | ||
1361 | |||
1362 | } | ||
1363 | |||
1364 | private float ClampInRange(float low, float val, float high) | ||
1365 | { | ||
1366 | return Math.Max(low, Math.Min(val, high)); | ||
1367 | // return Utils.Clamp(val, low, high); | ||
1368 | } | ||
1369 | |||
1370 | // Invoke the detailed logger and output something if it's enabled. | ||
1371 | private void VDetailLog(string msg, params Object[] args) | ||
1372 | { | ||
1373 | if (Prim.PhysicsScene.VehicleLoggingEnabled) | ||
1374 | Prim.PhysicsScene.DetailLog(msg, args); | ||
1375 | } | ||
1376 | } | ||
1377 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs new file mode 100644 index 0000000..845a113 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs | |||
@@ -0,0 +1,329 @@ | |||
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.BulletSNPlugin | ||
34 | { | ||
35 | |||
36 | // A BSPrim can get individual information about its linkedness attached | ||
37 | // to it through an instance of a subclass of LinksetInfo. | ||
38 | // Each type of linkset will define the information needed for its type. | ||
39 | public abstract class BSLinksetInfo | ||
40 | { | ||
41 | public virtual void Clear() { } | ||
42 | } | ||
43 | |||
44 | public abstract class BSLinkset | ||
45 | { | ||
46 | // private static string LogHeader = "[BULLETSIM LINKSET]"; | ||
47 | |||
48 | public enum LinksetImplementation | ||
49 | { | ||
50 | Constraint = 0, // linkset tied together with constraints | ||
51 | Compound = 1, // linkset tied together as a compound object | ||
52 | Manual = 2 // linkset tied together manually (code moves all the pieces) | ||
53 | } | ||
54 | // Create the correct type of linkset for this child | ||
55 | public static BSLinkset Factory(BSScene physScene, BSPhysObject parent) | ||
56 | { | ||
57 | BSLinkset ret = null; | ||
58 | |||
59 | switch ((int)BSParam.LinksetImplementation) | ||
60 | { | ||
61 | case (int)LinksetImplementation.Constraint: | ||
62 | ret = new BSLinksetConstraints(physScene, parent); | ||
63 | break; | ||
64 | case (int)LinksetImplementation.Compound: | ||
65 | ret = new BSLinksetCompound(physScene, parent); | ||
66 | break; | ||
67 | case (int)LinksetImplementation.Manual: | ||
68 | // ret = new BSLinksetManual(physScene, parent); | ||
69 | break; | ||
70 | default: | ||
71 | ret = new BSLinksetCompound(physScene, parent); | ||
72 | break; | ||
73 | } | ||
74 | return ret; | ||
75 | } | ||
76 | |||
77 | public BSPhysObject LinksetRoot { get; protected set; } | ||
78 | |||
79 | public BSScene PhysicsScene { get; private set; } | ||
80 | |||
81 | static int m_nextLinksetID = 1; | ||
82 | public int LinksetID { get; private set; } | ||
83 | |||
84 | // The children under the root in this linkset. | ||
85 | protected HashSet<BSPhysObject> m_children; | ||
86 | |||
87 | // We lock the diddling of linkset classes to prevent any badness. | ||
88 | // This locks the modification of the instances of this class. Changes | ||
89 | // to the physical representation is done via the tainting mechenism. | ||
90 | protected object m_linksetActivityLock = new Object(); | ||
91 | |||
92 | // Some linksets have a preferred physical shape. | ||
93 | // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. | ||
94 | public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | ||
95 | { | ||
96 | return BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
97 | } | ||
98 | |||
99 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims | ||
100 | public float LinksetMass { get; protected set; } | ||
101 | |||
102 | public virtual bool LinksetIsColliding { get { return false; } } | ||
103 | |||
104 | public OMV.Vector3 CenterOfMass | ||
105 | { | ||
106 | get { return ComputeLinksetCenterOfMass(); } | ||
107 | } | ||
108 | |||
109 | public OMV.Vector3 GeometricCenter | ||
110 | { | ||
111 | get { return ComputeLinksetGeometricCenter(); } | ||
112 | } | ||
113 | |||
114 | protected BSLinkset(BSScene scene, BSPhysObject parent) | ||
115 | { | ||
116 | // A simple linkset of one (no children) | ||
117 | LinksetID = m_nextLinksetID++; | ||
118 | // We create LOTS of linksets. | ||
119 | if (m_nextLinksetID <= 0) | ||
120 | m_nextLinksetID = 1; | ||
121 | PhysicsScene = scene; | ||
122 | LinksetRoot = parent; | ||
123 | m_children = new HashSet<BSPhysObject>(); | ||
124 | LinksetMass = parent.RawMass; | ||
125 | Rebuilding = false; | ||
126 | } | ||
127 | |||
128 | // Link to a linkset where the child knows the parent. | ||
129 | // Parent changing should not happen so do some sanity checking. | ||
130 | // We return the parent's linkset so the child can track its membership. | ||
131 | // Called at runtime. | ||
132 | public BSLinkset AddMeToLinkset(BSPhysObject child) | ||
133 | { | ||
134 | lock (m_linksetActivityLock) | ||
135 | { | ||
136 | // Don't add the root to its own linkset | ||
137 | if (!IsRoot(child)) | ||
138 | AddChildToLinkset(child); | ||
139 | LinksetMass = ComputeLinksetMass(); | ||
140 | } | ||
141 | return this; | ||
142 | } | ||
143 | |||
144 | // Remove a child from a linkset. | ||
145 | // Returns a new linkset for the child which is a linkset of one (just the | ||
146 | // orphened child). | ||
147 | // Called at runtime. | ||
148 | public BSLinkset RemoveMeFromLinkset(BSPhysObject child) | ||
149 | { | ||
150 | lock (m_linksetActivityLock) | ||
151 | { | ||
152 | if (IsRoot(child)) | ||
153 | { | ||
154 | // Cannot remove the root from a linkset. | ||
155 | return this; | ||
156 | } | ||
157 | RemoveChildFromLinkset(child); | ||
158 | LinksetMass = ComputeLinksetMass(); | ||
159 | } | ||
160 | |||
161 | // The child is down to a linkset of just itself | ||
162 | return BSLinkset.Factory(PhysicsScene, child); | ||
163 | } | ||
164 | |||
165 | // Return 'true' if the passed object is the root object of this linkset | ||
166 | public bool IsRoot(BSPhysObject requestor) | ||
167 | { | ||
168 | return (requestor.LocalID == LinksetRoot.LocalID); | ||
169 | } | ||
170 | |||
171 | public int NumberOfChildren { get { return m_children.Count; } } | ||
172 | |||
173 | // Return 'true' if this linkset has any children (more than the root member) | ||
174 | public bool HasAnyChildren { get { return (m_children.Count > 0); } } | ||
175 | |||
176 | // Return 'true' if this child is in this linkset | ||
177 | public bool HasChild(BSPhysObject child) | ||
178 | { | ||
179 | bool ret = false; | ||
180 | lock (m_linksetActivityLock) | ||
181 | { | ||
182 | ret = m_children.Contains(child); | ||
183 | /* Safer version but the above should work | ||
184 | foreach (BSPhysObject bp in m_children) | ||
185 | { | ||
186 | if (child.LocalID == bp.LocalID) | ||
187 | { | ||
188 | ret = true; | ||
189 | break; | ||
190 | } | ||
191 | } | ||
192 | */ | ||
193 | } | ||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | // Perform an action on each member of the linkset including root prim. | ||
198 | // Depends on the action on whether this should be done at taint time. | ||
199 | public delegate bool ForEachMemberAction(BSPhysObject obj); | ||
200 | public virtual bool ForEachMember(ForEachMemberAction action) | ||
201 | { | ||
202 | bool ret = false; | ||
203 | lock (m_linksetActivityLock) | ||
204 | { | ||
205 | action(LinksetRoot); | ||
206 | foreach (BSPhysObject po in m_children) | ||
207 | { | ||
208 | if (action(po)) | ||
209 | break; | ||
210 | } | ||
211 | } | ||
212 | return ret; | ||
213 | } | ||
214 | |||
215 | // I am the root of a linkset and a new child is being added | ||
216 | // Called while LinkActivity is locked. | ||
217 | protected abstract void AddChildToLinkset(BSPhysObject child); | ||
218 | |||
219 | // I am the root of a linkset and one of my children is being removed. | ||
220 | // Safe to call even if the child is not really in my linkset. | ||
221 | protected abstract void RemoveChildFromLinkset(BSPhysObject child); | ||
222 | |||
223 | // When physical properties are changed the linkset needs to recalculate | ||
224 | // its internal properties. | ||
225 | // May be called at runtime or taint-time. | ||
226 | public virtual void Refresh(BSPhysObject requestor) | ||
227 | { | ||
228 | LinksetMass = ComputeLinksetMass(); | ||
229 | } | ||
230 | |||
231 | // Flag denoting the linkset is in the process of being rebuilt. | ||
232 | // Used to know not the schedule a rebuild in the middle of a rebuild. | ||
233 | protected bool Rebuilding { get; set; } | ||
234 | |||
235 | // The object is going dynamic (physical). Do any setup necessary | ||
236 | // for a dynamic linkset. | ||
237 | // Only the state of the passed object can be modified. The rest of the linkset | ||
238 | // has not yet been fully constructed. | ||
239 | // Return 'true' if any properties updated on the passed object. | ||
240 | // Called at taint-time! | ||
241 | public abstract bool MakeDynamic(BSPhysObject child); | ||
242 | |||
243 | // The object is going static (non-physical). Do any setup necessary | ||
244 | // for a static linkset. | ||
245 | // Return 'true' if any properties updated on the passed object. | ||
246 | // Called at taint-time! | ||
247 | public abstract bool MakeStatic(BSPhysObject child); | ||
248 | |||
249 | // Called when a parameter update comes from the physics engine for any object | ||
250 | // of the linkset is received. | ||
251 | // Passed flag is update came from physics engine (true) or the user (false). | ||
252 | // Called at taint-time!! | ||
253 | public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate); | ||
254 | |||
255 | // Routine used when rebuilding the body of the root of the linkset | ||
256 | // Destroy all the constraints have have been made to root. | ||
257 | // This is called when the root body is changing. | ||
258 | // Returns 'true' of something was actually removed and would need restoring | ||
259 | // Called at taint-time!! | ||
260 | public abstract bool RemoveBodyDependencies(BSPrim child); | ||
261 | |||
262 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | ||
263 | // this routine will restore the removed constraints. | ||
264 | // Called at taint-time!! | ||
265 | public abstract void RestoreBodyDependencies(BSPrim child); | ||
266 | |||
267 | // ================================================================ | ||
268 | protected virtual float ComputeLinksetMass() | ||
269 | { | ||
270 | float mass = LinksetRoot.RawMass; | ||
271 | if (HasAnyChildren) | ||
272 | { | ||
273 | lock (m_linksetActivityLock) | ||
274 | { | ||
275 | foreach (BSPhysObject bp in m_children) | ||
276 | { | ||
277 | mass += bp.RawMass; | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | return mass; | ||
282 | } | ||
283 | |||
284 | protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() | ||
285 | { | ||
286 | OMV.Vector3 com; | ||
287 | lock (m_linksetActivityLock) | ||
288 | { | ||
289 | com = LinksetRoot.Position * LinksetRoot.RawMass; | ||
290 | float totalMass = LinksetRoot.RawMass; | ||
291 | |||
292 | foreach (BSPhysObject bp in m_children) | ||
293 | { | ||
294 | com += bp.Position * bp.RawMass; | ||
295 | totalMass += bp.RawMass; | ||
296 | } | ||
297 | if (totalMass != 0f) | ||
298 | com /= totalMass; | ||
299 | } | ||
300 | |||
301 | return com; | ||
302 | } | ||
303 | |||
304 | protected virtual OMV.Vector3 ComputeLinksetGeometricCenter() | ||
305 | { | ||
306 | OMV.Vector3 com; | ||
307 | lock (m_linksetActivityLock) | ||
308 | { | ||
309 | com = LinksetRoot.Position; | ||
310 | |||
311 | foreach (BSPhysObject bp in m_children) | ||
312 | { | ||
313 | com += bp.Position * bp.RawMass; | ||
314 | } | ||
315 | com /= (m_children.Count + 1); | ||
316 | } | ||
317 | |||
318 | return com; | ||
319 | } | ||
320 | |||
321 | // Invoke the detailed logger and output something if it's enabled. | ||
322 | protected void DetailLog(string msg, params Object[] args) | ||
323 | { | ||
324 | if (PhysicsScene.PhysicsLogging.Enabled) | ||
325 | PhysicsScene.DetailLog(msg, args); | ||
326 | } | ||
327 | |||
328 | } | ||
329 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs new file mode 100644 index 0000000..9a977e6 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs | |||
@@ -0,0 +1,397 @@ | |||
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.BulletSNPlugin | ||
36 | { | ||
37 | |||
38 | // When a child is linked, the relationship position of the child to the parent | ||
39 | // is remembered so the child's world position can be recomputed when it is | ||
40 | // removed from the linkset. | ||
41 | sealed class BSLinksetCompoundInfo : BSLinksetInfo | ||
42 | { | ||
43 | public OMV.Vector3 OffsetPos; | ||
44 | public OMV.Quaternion OffsetRot; | ||
45 | public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r) | ||
46 | { | ||
47 | OffsetPos = p; | ||
48 | OffsetRot = r; | ||
49 | } | ||
50 | public override void Clear() | ||
51 | { | ||
52 | OffsetPos = OMV.Vector3.Zero; | ||
53 | OffsetRot = OMV.Quaternion.Identity; | ||
54 | } | ||
55 | public override string ToString() | ||
56 | { | ||
57 | StringBuilder buff = new StringBuilder(); | ||
58 | buff.Append("<p="); | ||
59 | buff.Append(OffsetPos.ToString()); | ||
60 | buff.Append(",r="); | ||
61 | buff.Append(OffsetRot.ToString()); | ||
62 | buff.Append(">"); | ||
63 | return buff.ToString(); | ||
64 | } | ||
65 | }; | ||
66 | |||
67 | public sealed class BSLinksetCompound : BSLinkset | ||
68 | { | ||
69 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; | ||
70 | |||
71 | public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent) | ||
72 | { | ||
73 | } | ||
74 | |||
75 | // For compound implimented linksets, if there are children, use compound shape for the root. | ||
76 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | ||
77 | { | ||
78 | // Returning 'unknown' means we don't have a preference. | ||
79 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
80 | if (IsRoot(requestor) && HasAnyChildren) | ||
81 | { | ||
82 | ret = BSPhysicsShapeType.SHAPE_COMPOUND; | ||
83 | } | ||
84 | // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); | ||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | // When physical properties are changed the linkset needs to recalculate | ||
89 | // its internal properties. | ||
90 | public override void Refresh(BSPhysObject requestor) | ||
91 | { | ||
92 | base.Refresh(requestor); | ||
93 | |||
94 | // Something changed so do the rebuilding thing | ||
95 | // ScheduleRebuild(); | ||
96 | } | ||
97 | |||
98 | // Schedule a refresh to happen after all the other taint processing. | ||
99 | private void ScheduleRebuild(BSPhysObject requestor) | ||
100 | { | ||
101 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1}", | ||
102 | requestor.LocalID, Rebuilding); | ||
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 (!Rebuilding) | ||
106 | { | ||
107 | PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() | ||
108 | { | ||
109 | if (HasAnyChildren) | ||
110 | RecomputeLinksetCompound(); | ||
111 | }); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | // The object is going dynamic (physical). Do any setup necessary | ||
116 | // for a dynamic linkset. | ||
117 | // Only the state of the passed object can be modified. The rest of the linkset | ||
118 | // has not yet been fully constructed. | ||
119 | // Return 'true' if any properties updated on the passed object. | ||
120 | // Called at taint-time! | ||
121 | public override bool MakeDynamic(BSPhysObject child) | ||
122 | { | ||
123 | bool ret = false; | ||
124 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
125 | if (IsRoot(child)) | ||
126 | { | ||
127 | // The root is going dynamic. Make sure mass is properly set. | ||
128 | ScheduleRebuild(LinksetRoot); | ||
129 | } | ||
130 | else | ||
131 | { | ||
132 | // The origional prims are removed from the world as the shape of the root compound | ||
133 | // shape takes over. | ||
134 | BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
135 | BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | ||
136 | // We don't want collisions from the old linkset children. | ||
137 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
138 | |||
139 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
140 | |||
141 | ret = true; | ||
142 | } | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | // The object is going static (non-physical). Do any setup necessary for a static linkset. | ||
147 | // Return 'true' if any properties updated on the passed object. | ||
148 | // This doesn't normally happen -- OpenSim removes the objects from the physical | ||
149 | // world if it is a static linkset. | ||
150 | // Called at taint-time! | ||
151 | public override bool MakeStatic(BSPhysObject child) | ||
152 | { | ||
153 | bool ret = false; | ||
154 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
155 | if (IsRoot(child)) | ||
156 | { | ||
157 | ScheduleRebuild(LinksetRoot); | ||
158 | } | ||
159 | else | ||
160 | { | ||
161 | // The non-physical children can come back to life. | ||
162 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
163 | |||
164 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
165 | |||
166 | // Don't force activation so setting of DISABLE_SIMULATION can stay if used. | ||
167 | BulletSimAPI.Activate2(child.PhysBody.ptr, false); | ||
168 | ret = true; | ||
169 | } | ||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate) | ||
174 | { | ||
175 | // The user moving a child around requires the rebuilding of the linkset compound shape | ||
176 | // One problem is this happens when a border is crossed -- the simulator implementation | ||
177 | // is to store the position into the group which causes the move of the object | ||
178 | // but it also means all the child positions get updated. | ||
179 | // What would cause an unnecessary rebuild so we make sure the linkset is in a | ||
180 | // region before bothering to do a rebuild. | ||
181 | if (!IsRoot(updated) | ||
182 | && !physicalUpdate | ||
183 | && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) | ||
184 | { | ||
185 | updated.LinksetInfo = null; | ||
186 | ScheduleRebuild(updated); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | // Routine called when rebuilding the body of some member of the linkset. | ||
191 | // Since we don't keep in world relationships, do nothing unless it's a child changing. | ||
192 | // Returns 'true' of something was actually removed and would need restoring | ||
193 | // Called at taint-time!! | ||
194 | public override bool RemoveBodyDependencies(BSPrim child) | ||
195 | { | ||
196 | bool ret = false; | ||
197 | |||
198 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", | ||
199 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(), IsRoot(child)); | ||
200 | |||
201 | if (!IsRoot(child)) | ||
202 | { | ||
203 | // Because it is a convenient time, recompute child world position and rotation based on | ||
204 | // its position in the linkset. | ||
205 | RecomputeChildWorldPosition(child, true); | ||
206 | } | ||
207 | |||
208 | // Cannot schedule a refresh/rebuild here because this routine is called when | ||
209 | // the linkset is being rebuilt. | ||
210 | // InternalRefresh(LinksetRoot); | ||
211 | |||
212 | return ret; | ||
213 | } | ||
214 | |||
215 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | ||
216 | // this routine will restore the removed constraints. | ||
217 | // Called at taint-time!! | ||
218 | public override void RestoreBodyDependencies(BSPrim child) | ||
219 | { | ||
220 | } | ||
221 | |||
222 | // When the linkset is built, the child shape is added to the compound shape relative to the | ||
223 | // root shape. The linkset then moves around but this does not move the actual child | ||
224 | // prim. The child prim's location must be recomputed based on the location of the root shape. | ||
225 | private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime) | ||
226 | { | ||
227 | BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo; | ||
228 | if (lci != null) | ||
229 | { | ||
230 | if (inTaintTime) | ||
231 | { | ||
232 | OMV.Vector3 oldPos = child.RawPosition; | ||
233 | child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos; | ||
234 | child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
235 | DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}", | ||
236 | child.LocalID, oldPos, lci, child.RawPosition); | ||
237 | } | ||
238 | else | ||
239 | { | ||
240 | // TaintedObject is not used here so the raw position is set now and not at taint-time. | ||
241 | child.Position = LinksetRoot.RawPosition + lci.OffsetPos; | ||
242 | child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
243 | } | ||
244 | } | ||
245 | else | ||
246 | { | ||
247 | // This happens when children have been added to the linkset but the linkset | ||
248 | // has not been constructed yet. So like, at taint time, adding children to a linkset | ||
249 | // and then changing properties of the children (makePhysical, for instance) | ||
250 | // but the post-print action of actually rebuilding the linkset has not yet happened. | ||
251 | // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}", | ||
252 | // LogHeader, child.LocalID); | ||
253 | DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | // ================================================================ | ||
258 | |||
259 | // Add a new child to the linkset. | ||
260 | // Called while LinkActivity is locked. | ||
261 | protected override void AddChildToLinkset(BSPhysObject child) | ||
262 | { | ||
263 | if (!HasChild(child)) | ||
264 | { | ||
265 | m_children.Add(child); | ||
266 | |||
267 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | ||
268 | |||
269 | // Rebuild the compound shape with the new child shape included | ||
270 | ScheduleRebuild(child); | ||
271 | } | ||
272 | return; | ||
273 | } | ||
274 | |||
275 | // Remove the specified child from the linkset. | ||
276 | // Safe to call even if the child is not really in the linkset. | ||
277 | protected override void RemoveChildFromLinkset(BSPhysObject child) | ||
278 | { | ||
279 | if (m_children.Remove(child)) | ||
280 | { | ||
281 | DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | ||
282 | child.LocalID, | ||
283 | LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(), | ||
284 | child.LocalID, child.PhysBody.ptr.ToString()); | ||
285 | |||
286 | // Cause the child's body to be rebuilt and thus restored to normal operation | ||
287 | RecomputeChildWorldPosition(child, false); | ||
288 | child.ForceBodyShapeRebuild(false); | ||
289 | |||
290 | if (!HasAnyChildren) | ||
291 | { | ||
292 | // The linkset is now empty. The root needs rebuilding. | ||
293 | LinksetRoot.ForceBodyShapeRebuild(false); | ||
294 | } | ||
295 | else | ||
296 | { | ||
297 | // Rebuild the compound shape with the child removed | ||
298 | ScheduleRebuild(child); | ||
299 | } | ||
300 | } | ||
301 | return; | ||
302 | } | ||
303 | |||
304 | // Called before the simulation step to make sure the compound based linkset | ||
305 | // is all initialized. | ||
306 | // Constraint linksets are rebuilt every time. | ||
307 | // Note that this works for rebuilding just the root after a linkset is taken apart. | ||
308 | // Called at taint time!! | ||
309 | private void RecomputeLinksetCompound() | ||
310 | { | ||
311 | try | ||
312 | { | ||
313 | // Suppress rebuilding while rebuilding | ||
314 | Rebuilding = true; | ||
315 | |||
316 | // Cause the root shape to be rebuilt as a compound object with just the root in it | ||
317 | LinksetRoot.ForceBodyShapeRebuild(true); | ||
318 | |||
319 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | ||
320 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | ||
321 | |||
322 | // Add a shape for each of the other children in the linkset | ||
323 | ForEachMember(delegate(BSPhysObject cPrim) | ||
324 | { | ||
325 | if (!IsRoot(cPrim)) | ||
326 | { | ||
327 | // Compute the displacement of the child from the root of the linkset. | ||
328 | // This info is saved in the child prim so the relationship does not | ||
329 | // change over time and the new child position can be computed | ||
330 | // when the linkset is being disassembled (the linkset may have moved). | ||
331 | BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo; | ||
332 | if (lci == null) | ||
333 | { | ||
334 | // Each child position and rotation is given relative to the root. | ||
335 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | ||
336 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | ||
337 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | ||
338 | |||
339 | // Save relative position for recomputing child's world position after moving linkset. | ||
340 | lci = new BSLinksetCompoundInfo(displacementPos, displacementRot); | ||
341 | cPrim.LinksetInfo = lci; | ||
342 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci); | ||
343 | } | ||
344 | |||
345 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", | ||
346 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot); | ||
347 | |||
348 | if (cPrim.PhysShape.isNativeShape) | ||
349 | { | ||
350 | // A native shape is turning into a hull collision shape because native | ||
351 | // shapes are not shared so we have to hullify it so it will be tracked | ||
352 | // and freed at the correct time. This also solves the scaling problem | ||
353 | // (native shapes scaled but hull/meshes are assumed to not be). | ||
354 | // TODO: decide of the native shape can just be used in the compound shape. | ||
355 | // Use call to CreateGeomNonSpecial(). | ||
356 | BulletShape saveShape = cPrim.PhysShape; | ||
357 | cPrim.PhysShape.Clear(); // Don't let the create free the child's shape | ||
358 | // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null); | ||
359 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | ||
360 | BulletShape newShape = cPrim.PhysShape; | ||
361 | cPrim.PhysShape = saveShape; | ||
362 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos, lci.OffsetRot); | ||
363 | } | ||
364 | else | ||
365 | { | ||
366 | // For the shared shapes (meshes and hulls), just use the shape in the child. | ||
367 | // The reference count added here will be decremented when the compound shape | ||
368 | // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced). | ||
369 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | ||
370 | { | ||
371 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | ||
372 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | ||
373 | } | ||
374 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos, lci.OffsetRot); | ||
375 | } | ||
376 | } | ||
377 | return false; // 'false' says to move onto the next child in the list | ||
378 | }); | ||
379 | |||
380 | // With all of the linkset packed into the root prim, it has the mass of everyone. | ||
381 | LinksetMass = LinksetMass; | ||
382 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); | ||
383 | } | ||
384 | finally | ||
385 | { | ||
386 | Rebuilding = false; | ||
387 | } | ||
388 | |||
389 | BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); | ||
390 | |||
391 | // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets. | ||
392 | // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, | ||
393 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); | ||
394 | |||
395 | } | ||
396 | } | ||
397 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs new file mode 100644 index 0000000..46ff99f --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs | |||
@@ -0,0 +1,316 @@ | |||
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.BulletSNPlugin | ||
34 | { | ||
35 | public sealed class BSLinksetConstraints : BSLinkset | ||
36 | { | ||
37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; | ||
38 | |||
39 | public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent) | ||
40 | { | ||
41 | } | ||
42 | |||
43 | // When physical properties are changed the linkset needs to recalculate | ||
44 | // its internal properties. | ||
45 | // This is queued in the 'post taint' queue so the | ||
46 | // refresh will happen once after all the other taints are applied. | ||
47 | public override void Refresh(BSPhysObject requestor) | ||
48 | { | ||
49 | base.Refresh(requestor); | ||
50 | |||
51 | // Queue to happen after all the other taint processing | ||
52 | PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() | ||
53 | { | ||
54 | if (HasAnyChildren && IsRoot(requestor)) | ||
55 | RecomputeLinksetConstraints(); | ||
56 | }); | ||
57 | } | ||
58 | |||
59 | // The object is going dynamic (physical). Do any setup necessary | ||
60 | // for a dynamic linkset. | ||
61 | // Only the state of the passed object can be modified. The rest of the linkset | ||
62 | // has not yet been fully constructed. | ||
63 | // Return 'true' if any properties updated on the passed object. | ||
64 | // Called at taint-time! | ||
65 | public override bool MakeDynamic(BSPhysObject child) | ||
66 | { | ||
67 | // What is done for each object in BSPrim is what we want. | ||
68 | return false; | ||
69 | } | ||
70 | |||
71 | // The object is going static (non-physical). Do any setup necessary for a static linkset. | ||
72 | // Return 'true' if any properties updated on the passed object. | ||
73 | // This doesn't normally happen -- OpenSim removes the objects from the physical | ||
74 | // world if it is a static linkset. | ||
75 | // Called at taint-time! | ||
76 | public override bool MakeStatic(BSPhysObject child) | ||
77 | { | ||
78 | // What is done for each object in BSPrim is what we want. | ||
79 | return false; | ||
80 | } | ||
81 | |||
82 | // Called at taint-time!! | ||
83 | public override void UpdateProperties(BSPhysObject updated, bool inTaintTime) | ||
84 | { | ||
85 | // Nothing to do for constraints on property updates | ||
86 | } | ||
87 | |||
88 | // Routine called when rebuilding the body of some member of the linkset. | ||
89 | // Destroy all the constraints have have been made to root and set | ||
90 | // up to rebuild the constraints before the next simulation step. | ||
91 | // Returns 'true' of something was actually removed and would need restoring | ||
92 | // Called at taint-time!! | ||
93 | public override bool RemoveBodyDependencies(BSPrim child) | ||
94 | { | ||
95 | bool ret = false; | ||
96 | |||
97 | DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", | ||
98 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString()); | ||
99 | |||
100 | lock (m_linksetActivityLock) | ||
101 | { | ||
102 | // Just undo all the constraints for this linkset. Rebuild at the end of the step. | ||
103 | ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); | ||
104 | // Cause the constraints, et al to be rebuilt before the next simulation step. | ||
105 | Refresh(LinksetRoot); | ||
106 | } | ||
107 | return ret; | ||
108 | } | ||
109 | |||
110 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | ||
111 | // this routine will restore the removed constraints. | ||
112 | // Called at taint-time!! | ||
113 | public override void RestoreBodyDependencies(BSPrim child) | ||
114 | { | ||
115 | // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. | ||
116 | } | ||
117 | |||
118 | // ================================================================ | ||
119 | |||
120 | // Add a new child to the linkset. | ||
121 | // Called while LinkActivity is locked. | ||
122 | protected override void AddChildToLinkset(BSPhysObject child) | ||
123 | { | ||
124 | if (!HasChild(child)) | ||
125 | { | ||
126 | m_children.Add(child); | ||
127 | |||
128 | DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | ||
129 | |||
130 | // Cause constraints and assorted properties to be recomputed before the next simulation step. | ||
131 | Refresh(LinksetRoot); | ||
132 | } | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | // Remove the specified child from the linkset. | ||
137 | // Safe to call even if the child is not really in my linkset. | ||
138 | protected override void RemoveChildFromLinkset(BSPhysObject child) | ||
139 | { | ||
140 | if (m_children.Remove(child)) | ||
141 | { | ||
142 | BSPhysObject rootx = LinksetRoot; // capture the root and body as of now | ||
143 | BSPhysObject childx = child; | ||
144 | |||
145 | DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | ||
146 | childx.LocalID, | ||
147 | rootx.LocalID, rootx.PhysBody.ptr.ToString(), | ||
148 | childx.LocalID, childx.PhysBody.ptr.ToString()); | ||
149 | |||
150 | PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() | ||
151 | { | ||
152 | PhysicallyUnlinkAChildFromRoot(rootx, childx); | ||
153 | }); | ||
154 | // See that the linkset parameters are recomputed at the end of the taint time. | ||
155 | Refresh(LinksetRoot); | ||
156 | } | ||
157 | else | ||
158 | { | ||
159 | // Non-fatal occurance. | ||
160 | // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); | ||
161 | } | ||
162 | return; | ||
163 | } | ||
164 | |||
165 | // Create a constraint between me (root of linkset) and the passed prim (the child). | ||
166 | // Called at taint time! | ||
167 | private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) | ||
168 | { | ||
169 | // Don't build the constraint when asked. Put it off until just before the simulation step. | ||
170 | Refresh(rootPrim); | ||
171 | } | ||
172 | |||
173 | private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim) | ||
174 | { | ||
175 | // Zero motion for children so they don't interpolate | ||
176 | childPrim.ZeroMotion(true); | ||
177 | |||
178 | // Relative position normalized to the root prim | ||
179 | // Essentually a vector pointing from center of rootPrim to center of childPrim | ||
180 | OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position; | ||
181 | |||
182 | // real world coordinate of midpoint between the two objects | ||
183 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); | ||
184 | |||
185 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", | ||
186 | rootPrim.LocalID, | ||
187 | rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString(), | ||
188 | childPrim.LocalID, childPrim.PhysBody.ptr.ToString(), | ||
189 | rootPrim.Position, childPrim.Position, midPoint); | ||
190 | |||
191 | // create a constraint that allows no freedom of movement between the two objects | ||
192 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | ||
193 | |||
194 | BSConstraint6Dof constrain = new BSConstraint6Dof( | ||
195 | PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); | ||
196 | // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); | ||
197 | |||
198 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. | ||
199 | * Using the midpoint is easier since it lets the Bullet code manipulate the transforms | ||
200 | * of the objects. | ||
201 | * Code left for future programmers. | ||
202 | // ================================================================================== | ||
203 | // relative position normalized to the root prim | ||
204 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); | ||
205 | OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation; | ||
206 | |||
207 | // relative rotation of the child to the parent | ||
208 | OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; | ||
209 | OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); | ||
210 | |||
211 | DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); | ||
212 | BS6DofConstraint constrain = new BS6DofConstraint( | ||
213 | PhysicsScene.World, rootPrim.Body, childPrim.Body, | ||
214 | OMV.Vector3.Zero, | ||
215 | OMV.Quaternion.Inverse(rootPrim.Orientation), | ||
216 | OMV.Vector3.Zero, | ||
217 | OMV.Quaternion.Inverse(childPrim.Orientation), | ||
218 | true, | ||
219 | true | ||
220 | ); | ||
221 | // ================================================================================== | ||
222 | */ | ||
223 | |||
224 | PhysicsScene.Constraints.AddConstraint(constrain); | ||
225 | |||
226 | // zero linear and angular limits makes the objects unable to move in relation to each other | ||
227 | constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
228 | constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
229 | |||
230 | // tweek the constraint to increase stability | ||
231 | constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset)); | ||
232 | constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor), | ||
233 | BSParam.LinkConstraintTransMotorMaxVel, | ||
234 | BSParam.LinkConstraintTransMotorMaxForce); | ||
235 | constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP); | ||
236 | if (BSParam.LinkConstraintSolverIterations != 0f) | ||
237 | { | ||
238 | constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations); | ||
239 | } | ||
240 | return constrain; | ||
241 | } | ||
242 | |||
243 | // Remove linkage between the linkset root and a particular child | ||
244 | // The root and child bodies are passed in because we need to remove the constraint between | ||
245 | // the bodies that were present at unlink time. | ||
246 | // Called at taint time! | ||
247 | private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) | ||
248 | { | ||
249 | bool ret = false; | ||
250 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", | ||
251 | rootPrim.LocalID, | ||
252 | rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString(), | ||
253 | childPrim.LocalID, childPrim.PhysBody.ptr.ToString()); | ||
254 | |||
255 | // Find the constraint for this link and get rid of it from the overall collection and from my list | ||
256 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) | ||
257 | { | ||
258 | // Make the child refresh its location | ||
259 | BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr); | ||
260 | ret = true; | ||
261 | } | ||
262 | |||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | // Remove linkage between myself and any possible children I might have. | ||
267 | // Returns 'true' of any constraints were destroyed. | ||
268 | // Called at taint time! | ||
269 | private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) | ||
270 | { | ||
271 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | ||
272 | |||
273 | return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); | ||
274 | } | ||
275 | |||
276 | // Call each of the constraints that make up this linkset and recompute the | ||
277 | // various transforms and variables. Create constraints of not created yet. | ||
278 | // Called before the simulation step to make sure the constraint based linkset | ||
279 | // is all initialized. | ||
280 | // Called at taint time!! | ||
281 | private void RecomputeLinksetConstraints() | ||
282 | { | ||
283 | float linksetMass = LinksetMass; | ||
284 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true); | ||
285 | |||
286 | // DEBUG: see of inter-linkset collisions are causing problems | ||
287 | // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, | ||
288 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); | ||
289 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", | ||
290 | LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(), linksetMass); | ||
291 | |||
292 | foreach (BSPhysObject child in m_children) | ||
293 | { | ||
294 | // A child in the linkset physically shows the mass of the whole linkset. | ||
295 | // This allows Bullet to apply enough force on the child to move the whole linkset. | ||
296 | // (Also do the mass stuff before recomputing the constraint so mass is not zero.) | ||
297 | child.UpdatePhysicalMassProperties(linksetMass, true); | ||
298 | |||
299 | BSConstraint constrain; | ||
300 | if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) | ||
301 | { | ||
302 | // If constraint doesn't exist yet, create it. | ||
303 | constrain = BuildConstraint(LinksetRoot, child); | ||
304 | } | ||
305 | constrain.RecomputeConstraintVariables(linksetMass); | ||
306 | |||
307 | // DEBUG: see of inter-linkset collisions are causing problems | ||
308 | // BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr, | ||
309 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); | ||
310 | |||
311 | // BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG | ||
312 | } | ||
313 | |||
314 | } | ||
315 | } | ||
316 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSMaterials.cs new file mode 100644 index 0000000..d7941b6 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSMaterials.cs | |||
@@ -0,0 +1,200 @@ | |||
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.BulletSNPlugin | ||
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 | MaterialAttributes thisAttrib = Attributes[matType]; | ||
184 | FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); | ||
185 | if (fieldInfo != null) | ||
186 | { | ||
187 | fieldInfo.SetValue(thisAttrib, val); | ||
188 | Attributes[matType] = thisAttrib; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | // Given a material type, return a structure of attributes. | ||
193 | public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) | ||
194 | { | ||
195 | int ind = (int)type; | ||
196 | if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; | ||
197 | return Attributes[ind]; | ||
198 | } | ||
199 | } | ||
200 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs new file mode 100644 index 0000000..7abc9b2 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs | |||
@@ -0,0 +1,347 @@ | |||
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.BulletSNPlugin | ||
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 | if (PhysicsScene.VehicleLoggingEnabled) | ||
63 | { | ||
64 | PhysicsScene.DetailLog(msg, parms); | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
70 | // Motor which moves CurrentValue to TargetValue over TimeScale seconds. | ||
71 | // The TargetValue decays in TargetValueDecayTimeScale and | ||
72 | // the CurrentValue will be held back by FrictionTimeScale. | ||
73 | // This motor will "zero itself" over time in that the targetValue will | ||
74 | // decay to zero and the currentValue will follow it to that zero. | ||
75 | // The overall effect is for the returned correction value to go from large | ||
76 | // values (the total difference between current and target minus friction) | ||
77 | // to small and eventually zero values. | ||
78 | // TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. | ||
79 | |||
80 | // For instance, if something is moving at speed X and the desired speed is Y, | ||
81 | // CurrentValue is X and TargetValue is Y. As the motor is stepped, new | ||
82 | // values of CurrentValue are returned that approach the TargetValue. | ||
83 | // The feature of decaying TargetValue is so vehicles will eventually | ||
84 | // come to a stop rather than run forever. This can be disabled by | ||
85 | // setting TargetValueDecayTimescale to 'infinite'. | ||
86 | // The change from CurrentValue to TargetValue is linear over TimeScale seconds. | ||
87 | public class BSVMotor : BSMotor | ||
88 | { | ||
89 | // public Vector3 FrameOfReference { get; set; } | ||
90 | // public Vector3 Offset { get; set; } | ||
91 | |||
92 | public virtual float TimeScale { get; set; } | ||
93 | public virtual float TargetValueDecayTimeScale { get; set; } | ||
94 | public virtual Vector3 FrictionTimescale { get; set; } | ||
95 | public virtual float Efficiency { get; set; } | ||
96 | |||
97 | public virtual float ErrorZeroThreshold { get; set; } | ||
98 | |||
99 | public virtual Vector3 TargetValue { get; protected set; } | ||
100 | public virtual Vector3 CurrentValue { get; protected set; } | ||
101 | public virtual Vector3 LastError { get; protected set; } | ||
102 | |||
103 | public virtual bool ErrorIsZero | ||
104 | { get { | ||
105 | return (LastError == Vector3.Zero || LastError.LengthSquared() <= ErrorZeroThreshold); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | public BSVMotor(string useName) | ||
110 | : base(useName) | ||
111 | { | ||
112 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; | ||
113 | Efficiency = 1f; | ||
114 | FrictionTimescale = BSMotor.InfiniteVector; | ||
115 | CurrentValue = TargetValue = Vector3.Zero; | ||
116 | ErrorZeroThreshold = 0.001f; | ||
117 | } | ||
118 | public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) | ||
119 | : this(useName) | ||
120 | { | ||
121 | TimeScale = timeScale; | ||
122 | TargetValueDecayTimeScale = decayTimeScale; | ||
123 | FrictionTimescale = frictionTimeScale; | ||
124 | Efficiency = efficiency; | ||
125 | CurrentValue = TargetValue = Vector3.Zero; | ||
126 | } | ||
127 | public void SetCurrent(Vector3 current) | ||
128 | { | ||
129 | CurrentValue = current; | ||
130 | } | ||
131 | public void SetTarget(Vector3 target) | ||
132 | { | ||
133 | TargetValue = target; | ||
134 | } | ||
135 | public override void Zero() | ||
136 | { | ||
137 | base.Zero(); | ||
138 | CurrentValue = TargetValue = Vector3.Zero; | ||
139 | } | ||
140 | |||
141 | // Compute the next step and return the new current value | ||
142 | public virtual Vector3 Step(float timeStep) | ||
143 | { | ||
144 | if (!Enabled) return TargetValue; | ||
145 | |||
146 | Vector3 origTarget = TargetValue; // DEBUG | ||
147 | Vector3 origCurrVal = CurrentValue; // DEBUG | ||
148 | |||
149 | Vector3 correction = Vector3.Zero; | ||
150 | Vector3 error = TargetValue - CurrentValue; | ||
151 | if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) | ||
152 | { | ||
153 | correction = Step(timeStep, error); | ||
154 | |||
155 | CurrentValue += correction; | ||
156 | |||
157 | // The desired value reduces to zero which also reduces the difference with current. | ||
158 | // If the decay time is infinite, don't decay at all. | ||
159 | float decayFactor = 0f; | ||
160 | if (TargetValueDecayTimeScale != BSMotor.Infinite) | ||
161 | { | ||
162 | decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | ||
163 | TargetValue *= (1f - decayFactor); | ||
164 | } | ||
165 | |||
166 | // The amount we can correct the error is reduced by the friction | ||
167 | Vector3 frictionFactor = Vector3.Zero; | ||
168 | if (FrictionTimescale != BSMotor.InfiniteVector) | ||
169 | { | ||
170 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
171 | // Individual friction components can be 'infinite' so compute each separately. | ||
172 | frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X); | ||
173 | frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y); | ||
174 | frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z); | ||
175 | frictionFactor *= timeStep; | ||
176 | CurrentValue *= (Vector3.One - frictionFactor); | ||
177 | } | ||
178 | |||
179 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", | ||
180 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | ||
181 | timeStep, error, correction); | ||
182 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", | ||
183 | BSScene.DetailLogZero, UseName, | ||
184 | TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor, | ||
185 | TargetValue, CurrentValue); | ||
186 | } | ||
187 | else | ||
188 | { | ||
189 | // Difference between what we have and target is small. Motor is done. | ||
190 | CurrentValue = TargetValue; | ||
191 | MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", | ||
192 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); | ||
193 | } | ||
194 | |||
195 | return CurrentValue; | ||
196 | } | ||
197 | public virtual Vector3 Step(float timeStep, Vector3 error) | ||
198 | { | ||
199 | if (!Enabled) return Vector3.Zero; | ||
200 | |||
201 | LastError = error; | ||
202 | Vector3 returnCorrection = Vector3.Zero; | ||
203 | if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) | ||
204 | { | ||
205 | // correction = error / secondsItShouldTakeToCorrect | ||
206 | Vector3 correctionAmount; | ||
207 | if (TimeScale == 0f || TimeScale == BSMotor.Infinite) | ||
208 | correctionAmount = error * timeStep; | ||
209 | else | ||
210 | correctionAmount = error / TimeScale * timeStep; | ||
211 | |||
212 | returnCorrection = correctionAmount; | ||
213 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", | ||
214 | BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); | ||
215 | } | ||
216 | return returnCorrection; | ||
217 | } | ||
218 | |||
219 | // The user sets all the parameters and calls this which outputs values until error is zero. | ||
220 | public override void GenerateTestOutput(float timeStep) | ||
221 | { | ||
222 | // maximum number of outputs to generate. | ||
223 | int maxOutput = 50; | ||
224 | MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); | ||
225 | MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}", | ||
226 | BSScene.DetailLogZero, UseName, | ||
227 | TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, | ||
228 | CurrentValue, TargetValue); | ||
229 | |||
230 | LastError = BSMotor.InfiniteVector; | ||
231 | while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) | ||
232 | { | ||
233 | Vector3 lastStep = Step(timeStep); | ||
234 | MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}", | ||
235 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); | ||
236 | } | ||
237 | MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); | ||
238 | |||
239 | |||
240 | } | ||
241 | |||
242 | public override string ToString() | ||
243 | { | ||
244 | return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>", | ||
245 | UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | public class BSFMotor : BSMotor | ||
250 | { | ||
251 | public float TimeScale { get; set; } | ||
252 | public float DecayTimeScale { get; set; } | ||
253 | public float Friction { get; set; } | ||
254 | public float Efficiency { get; set; } | ||
255 | |||
256 | public float Target { get; private set; } | ||
257 | public float CurrentValue { get; private set; } | ||
258 | |||
259 | public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) | ||
260 | : base(useName) | ||
261 | { | ||
262 | } | ||
263 | public void SetCurrent(float target) | ||
264 | { | ||
265 | } | ||
266 | public void SetTarget(float target) | ||
267 | { | ||
268 | } | ||
269 | public virtual float Step(float timeStep) | ||
270 | { | ||
271 | return 0f; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | // Proportional, Integral, Derivitive Motor | ||
276 | // Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. | ||
277 | public class BSPIDVMotor : BSVMotor | ||
278 | { | ||
279 | // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10. | ||
280 | public Vector3 proportionFactor { get; set; } | ||
281 | public Vector3 integralFactor { get; set; } | ||
282 | public Vector3 derivFactor { get; set; } | ||
283 | |||
284 | // Arbritrary factor range. | ||
285 | // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. | ||
286 | public float EfficiencyHigh = 0.4f; | ||
287 | public float EfficiencyLow = 4.0f; | ||
288 | |||
289 | // Running integration of the error | ||
290 | Vector3 RunningIntegration { get; set; } | ||
291 | |||
292 | public BSPIDVMotor(string useName) | ||
293 | : base(useName) | ||
294 | { | ||
295 | proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||
296 | integralFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||
297 | derivFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||
298 | RunningIntegration = Vector3.Zero; | ||
299 | LastError = Vector3.Zero; | ||
300 | } | ||
301 | |||
302 | public override void Zero() | ||
303 | { | ||
304 | base.Zero(); | ||
305 | } | ||
306 | |||
307 | public override float Efficiency | ||
308 | { | ||
309 | get { return base.Efficiency; } | ||
310 | set | ||
311 | { | ||
312 | base.Efficiency = Util.Clamp(value, 0f, 1f); | ||
313 | // Compute factors based on efficiency. | ||
314 | // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot. | ||
315 | // If efficiency is low (0f), use a factor value that overcorrects. | ||
316 | // TODO: might want to vary contribution of different factor depending on efficiency. | ||
317 | float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; | ||
318 | // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; | ||
319 | proportionFactor = new Vector3(factor, factor, factor); | ||
320 | integralFactor = new Vector3(factor, factor, factor); | ||
321 | derivFactor = new Vector3(factor, factor, factor); | ||
322 | } | ||
323 | } | ||
324 | |||
325 | // Ignore Current and Target Values and just advance the PID computation on this error. | ||
326 | public override Vector3 Step(float timeStep, Vector3 error) | ||
327 | { | ||
328 | if (!Enabled) return Vector3.Zero; | ||
329 | |||
330 | // Add up the error so we can integrate over the accumulated errors | ||
331 | RunningIntegration += error * timeStep; | ||
332 | |||
333 | // A simple derivitive is the rate of change from the last error. | ||
334 | Vector3 derivFactor = (error - LastError) * timeStep; | ||
335 | LastError = error; | ||
336 | |||
337 | // Correction = -(proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) | ||
338 | Vector3 ret = -( | ||
339 | error * proportionFactor | ||
340 | + RunningIntegration * integralFactor | ||
341 | + derivFactor * derivFactor | ||
342 | ); | ||
343 | |||
344 | return ret; | ||
345 | } | ||
346 | } | ||
347 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs new file mode 100644 index 0000000..5e93a03 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs | |||
@@ -0,0 +1,559 @@ | |||
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.Physics.Manager; | ||
32 | |||
33 | using OpenMetaverse; | ||
34 | using Nini.Config; | ||
35 | |||
36 | namespace OpenSim.Region.Physics.BulletSNPlugin | ||
37 | { | ||
38 | public static class BSParam | ||
39 | { | ||
40 | // Level of Detail values kept as float because that's what the Meshmerizer wants | ||
41 | public static float MeshLOD { get; private set; } | ||
42 | public static float MeshMegaPrimLOD { get; private set; } | ||
43 | public static float MeshMegaPrimThreshold { get; private set; } | ||
44 | public static float SculptLOD { get; private set; } | ||
45 | |||
46 | public static float MinimumObjectMass { get; private set; } | ||
47 | public static float MaximumObjectMass { get; private set; } | ||
48 | |||
49 | public static float LinearDamping { get; private set; } | ||
50 | public static float AngularDamping { get; private set; } | ||
51 | public static float DeactivationTime { get; private set; } | ||
52 | public static float LinearSleepingThreshold { get; private set; } | ||
53 | public static float AngularSleepingThreshold { get; private set; } | ||
54 | public static float CcdMotionThreshold { get; private set; } | ||
55 | public static float CcdSweptSphereRadius { get; private set; } | ||
56 | public static float ContactProcessingThreshold { get; private set; } | ||
57 | |||
58 | public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed | ||
59 | public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes | ||
60 | public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects | ||
61 | |||
62 | public static float TerrainImplementation { get; private set; } | ||
63 | public static float TerrainFriction { get; private set; } | ||
64 | public static float TerrainHitFraction { get; private set; } | ||
65 | public static float TerrainRestitution { get; private set; } | ||
66 | public static float TerrainCollisionMargin { get; private set; } | ||
67 | |||
68 | // Avatar parameters | ||
69 | public static float AvatarFriction { get; private set; } | ||
70 | public static float AvatarStandingFriction { get; private set; } | ||
71 | public static float AvatarDensity { get; private set; } | ||
72 | public static float AvatarRestitution { get; private set; } | ||
73 | public static float AvatarCapsuleWidth { get; private set; } | ||
74 | public static float AvatarCapsuleDepth { get; private set; } | ||
75 | public static float AvatarCapsuleHeight { get; private set; } | ||
76 | public static float AvatarContactProcessingThreshold { get; private set; } | ||
77 | |||
78 | public static float VehicleAngularDamping { get; private set; } | ||
79 | |||
80 | public static float LinksetImplementation { get; private set; } | ||
81 | public static float LinkConstraintUseFrameOffset { get; private set; } | ||
82 | public static float LinkConstraintEnableTransMotor { get; private set; } | ||
83 | public static float LinkConstraintTransMotorMaxVel { get; private set; } | ||
84 | public static float LinkConstraintTransMotorMaxForce { get; private set; } | ||
85 | public static float LinkConstraintERP { get; private set; } | ||
86 | public static float LinkConstraintCFM { get; private set; } | ||
87 | public static float LinkConstraintSolverIterations { get; private set; } | ||
88 | |||
89 | public static float PID_D { get; private set; } // derivative | ||
90 | public static float PID_P { get; private set; } // proportional | ||
91 | |||
92 | public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); | ||
93 | public delegate float ParamGet(BSScene scene); | ||
94 | public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); | ||
95 | public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val); | ||
96 | |||
97 | public struct ParameterDefn | ||
98 | { | ||
99 | public string name; // string name of the parameter | ||
100 | public string desc; // a short description of what the parameter means | ||
101 | public float defaultValue; // default value if not specified anywhere else | ||
102 | public ParamUser userParam; // get the value from the configuration file | ||
103 | public ParamGet getter; // return the current value stored for this parameter | ||
104 | public ParamSet setter; // set the current value for this parameter | ||
105 | public SetOnObject onObject; // set the value on an object in the physical domain | ||
106 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) | ||
107 | { | ||
108 | name = n; | ||
109 | desc = d; | ||
110 | defaultValue = v; | ||
111 | userParam = u; | ||
112 | getter = g; | ||
113 | setter = s; | ||
114 | onObject = null; | ||
115 | } | ||
116 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o) | ||
117 | { | ||
118 | name = n; | ||
119 | desc = d; | ||
120 | defaultValue = v; | ||
121 | userParam = u; | ||
122 | getter = g; | ||
123 | setter = s; | ||
124 | onObject = o; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | // List of all of the externally visible parameters. | ||
129 | // For each parameter, this table maps a text name to getter and setters. | ||
130 | // To add a new externally referencable/settable parameter, add the paramter storage | ||
131 | // location somewhere in the program and make an entry in this table with the | ||
132 | // getters and setters. | ||
133 | // It is easiest to find an existing definition and copy it. | ||
134 | // Parameter values are floats. Booleans are converted to a floating value. | ||
135 | // | ||
136 | // A ParameterDefn() takes the following parameters: | ||
137 | // -- the text name of the parameter. This is used for console input and ini file. | ||
138 | // -- a short text description of the parameter. This shows up in the console listing. | ||
139 | // -- a default value (float) | ||
140 | // -- a delegate for fetching the parameter from the ini file. | ||
141 | // Should handle fetching the right type from the ini file and converting it. | ||
142 | // -- a delegate for getting the value as a float | ||
143 | // -- a delegate for setting the value from a float | ||
144 | // -- an optional delegate to update the value in the world. Most often used to | ||
145 | // push the new value to an in-world object. | ||
146 | // | ||
147 | // The single letter parameters for the delegates are: | ||
148 | // s = BSScene | ||
149 | // o = BSPhysObject | ||
150 | // p = string parameter name | ||
151 | // l = localID of referenced object | ||
152 | // v = value (float) | ||
153 | // cf = parameter configuration class (for fetching values from ini file) | ||
154 | private static ParameterDefn[] ParameterDefinitions = | ||
155 | { | ||
156 | new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", | ||
157 | ConfigurationParameters.numericTrue, | ||
158 | (s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, | ||
159 | (s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); }, | ||
160 | (s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ), | ||
161 | new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", | ||
162 | ConfigurationParameters.numericFalse, | ||
163 | (s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, | ||
164 | (s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); }, | ||
165 | (s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ), | ||
166 | new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", | ||
167 | ConfigurationParameters.numericTrue, | ||
168 | (s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, | ||
169 | (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); }, | ||
170 | (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ), | ||
171 | |||
172 | new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | ||
173 | 8f, | ||
174 | (s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); }, | ||
175 | (s) => { return MeshLOD; }, | ||
176 | (s,p,l,v) => { MeshLOD = v; } ), | ||
177 | new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", | ||
178 | 16f, | ||
179 | (s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); }, | ||
180 | (s) => { return MeshMegaPrimLOD; }, | ||
181 | (s,p,l,v) => { MeshMegaPrimLOD = v; } ), | ||
182 | new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", | ||
183 | 10f, | ||
184 | (s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); }, | ||
185 | (s) => { return MeshMegaPrimThreshold; }, | ||
186 | (s,p,l,v) => { MeshMegaPrimThreshold = v; } ), | ||
187 | new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", | ||
188 | 32f, | ||
189 | (s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); }, | ||
190 | (s) => { return SculptLOD; }, | ||
191 | (s,p,l,v) => { SculptLOD = v; } ), | ||
192 | |||
193 | new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", | ||
194 | 10f, | ||
195 | (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); }, | ||
196 | (s) => { return (float)s.m_maxSubSteps; }, | ||
197 | (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ), | ||
198 | new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", | ||
199 | 1f / 60f, | ||
200 | (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); }, | ||
201 | (s) => { return (float)s.m_fixedTimeStep; }, | ||
202 | (s,p,l,v) => { s.m_fixedTimeStep = v; } ), | ||
203 | new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", | ||
204 | 2048f, | ||
205 | (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); }, | ||
206 | (s) => { return (float)s.m_maxCollisionsPerFrame; }, | ||
207 | (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), | ||
208 | new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame", | ||
209 | 8000f, | ||
210 | (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, | ||
211 | (s) => { return (float)s.m_maxUpdatesPerFrame; }, | ||
212 | (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), | ||
213 | new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", | ||
214 | 500f, | ||
215 | (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, | ||
216 | (s) => { return (float)s.m_taintsToProcessPerStep; }, | ||
217 | (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), | ||
218 | new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)", | ||
219 | 0.0001f, | ||
220 | (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); }, | ||
221 | (s) => { return (float)MinimumObjectMass; }, | ||
222 | (s,p,l,v) => { MinimumObjectMass = v; } ), | ||
223 | new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", | ||
224 | 10000.01f, | ||
225 | (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); }, | ||
226 | (s) => { return (float)MaximumObjectMass; }, | ||
227 | (s,p,l,v) => { MaximumObjectMass = v; } ), | ||
228 | |||
229 | new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", | ||
230 | 2200f, | ||
231 | (s,cf,p,v) => { PID_D = cf.GetFloat(p, v); }, | ||
232 | (s) => { return (float)PID_D; }, | ||
233 | (s,p,l,v) => { PID_D = v; } ), | ||
234 | new ParameterDefn("PID_P", "Parameteric factor for motion smoothing", | ||
235 | 900f, | ||
236 | (s,cf,p,v) => { PID_P = cf.GetFloat(p, v); }, | ||
237 | (s) => { return (float)PID_P; }, | ||
238 | (s,p,l,v) => { PID_P = v; } ), | ||
239 | |||
240 | new ParameterDefn("DefaultFriction", "Friction factor used on new objects", | ||
241 | 0.2f, | ||
242 | (s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); }, | ||
243 | (s) => { return s.UnmanagedParams[0].defaultFriction; }, | ||
244 | (s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ), | ||
245 | new ParameterDefn("DefaultDensity", "Density for new objects" , | ||
246 | 10.000006836f, // Aluminum g/cm3 | ||
247 | (s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); }, | ||
248 | (s) => { return s.UnmanagedParams[0].defaultDensity; }, | ||
249 | (s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ), | ||
250 | new ParameterDefn("DefaultRestitution", "Bouncyness of an object" , | ||
251 | 0f, | ||
252 | (s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); }, | ||
253 | (s) => { return s.UnmanagedParams[0].defaultRestitution; }, | ||
254 | (s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ), | ||
255 | new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", | ||
256 | 0.04f, | ||
257 | (s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); }, | ||
258 | (s) => { return s.UnmanagedParams[0].collisionMargin; }, | ||
259 | (s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ), | ||
260 | new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)", | ||
261 | -9.80665f, | ||
262 | (s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); }, | ||
263 | (s) => { return s.UnmanagedParams[0].gravity; }, | ||
264 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); }, | ||
265 | (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ), | ||
266 | |||
267 | |||
268 | new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", | ||
269 | 0f, | ||
270 | (s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); }, | ||
271 | (s) => { return LinearDamping; }, | ||
272 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); }, | ||
273 | (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, AngularDamping); } ), | ||
274 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", | ||
275 | 0f, | ||
276 | (s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); }, | ||
277 | (s) => { return AngularDamping; }, | ||
278 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); }, | ||
279 | (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, LinearDamping, v); } ), | ||
280 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", | ||
281 | 0.2f, | ||
282 | (s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); }, | ||
283 | (s) => { return DeactivationTime; }, | ||
284 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); }, | ||
285 | (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ), | ||
286 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", | ||
287 | 0.8f, | ||
288 | (s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); }, | ||
289 | (s) => { return LinearSleepingThreshold; }, | ||
290 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); }, | ||
291 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), | ||
292 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", | ||
293 | 1.0f, | ||
294 | (s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); }, | ||
295 | (s) => { return AngularSleepingThreshold; }, | ||
296 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); }, | ||
297 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), | ||
298 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , | ||
299 | 0f, // set to zero to disable | ||
300 | (s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); }, | ||
301 | (s) => { return CcdMotionThreshold; }, | ||
302 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); }, | ||
303 | (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ), | ||
304 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , | ||
305 | 0f, | ||
306 | (s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); }, | ||
307 | (s) => { return CcdSweptSphereRadius; }, | ||
308 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); }, | ||
309 | (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ), | ||
310 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , | ||
311 | 0.1f, | ||
312 | (s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); }, | ||
313 | (s) => { return ContactProcessingThreshold; }, | ||
314 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); }, | ||
315 | (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ), | ||
316 | |||
317 | new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", | ||
318 | (float)BSTerrainPhys.TerrainImplementation.Heightmap, | ||
319 | (s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); }, | ||
320 | (s) => { return TerrainImplementation; }, | ||
321 | (s,p,l,v) => { TerrainImplementation = v; } ), | ||
322 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | ||
323 | 0.3f, | ||
324 | (s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); }, | ||
325 | (s) => { return TerrainFriction; }, | ||
326 | (s,p,l,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ), | ||
327 | new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , | ||
328 | 0.8f, | ||
329 | (s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); }, | ||
330 | (s) => { return TerrainHitFraction; }, | ||
331 | (s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ), | ||
332 | new ParameterDefn("TerrainRestitution", "Bouncyness" , | ||
333 | 0f, | ||
334 | (s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); }, | ||
335 | (s) => { return TerrainRestitution; }, | ||
336 | (s,p,l,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ), | ||
337 | new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , | ||
338 | 0.04f, | ||
339 | (s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); }, | ||
340 | (s) => { return TerrainCollisionMargin; }, | ||
341 | (s,p,l,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ), | ||
342 | |||
343 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | ||
344 | 0.2f, | ||
345 | (s,cf,p,v) => { AvatarFriction = cf.GetFloat(p, v); }, | ||
346 | (s) => { return AvatarFriction; }, | ||
347 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ), | ||
348 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | ||
349 | 10.0f, | ||
350 | (s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); }, | ||
351 | (s) => { return AvatarStandingFriction; }, | ||
352 | (s,p,l,v) => { AvatarStandingFriction = v; } ), | ||
353 | new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | ||
354 | 3.5f, | ||
355 | (s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); }, | ||
356 | (s) => { return AvatarDensity; }, | ||
357 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ), | ||
358 | new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", | ||
359 | 0f, | ||
360 | (s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); }, | ||
361 | (s) => { return AvatarRestitution; }, | ||
362 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ), | ||
363 | new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", | ||
364 | 0.6f, | ||
365 | (s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); }, | ||
366 | (s) => { return AvatarCapsuleWidth; }, | ||
367 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ), | ||
368 | new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", | ||
369 | 0.45f, | ||
370 | (s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); }, | ||
371 | (s) => { return AvatarCapsuleDepth; }, | ||
372 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ), | ||
373 | new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", | ||
374 | 1.5f, | ||
375 | (s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); }, | ||
376 | (s) => { return AvatarCapsuleHeight; }, | ||
377 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ), | ||
378 | new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | ||
379 | 0.1f, | ||
380 | (s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); }, | ||
381 | (s) => { return AvatarContactProcessingThreshold; }, | ||
382 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ), | ||
383 | |||
384 | new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", | ||
385 | 0.95f, | ||
386 | (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); }, | ||
387 | (s) => { return VehicleAngularDamping; }, | ||
388 | (s,p,l,v) => { VehicleAngularDamping = v; } ), | ||
389 | |||
390 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | ||
391 | 0f, | ||
392 | (s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, | ||
393 | (s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; }, | ||
394 | (s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ), | ||
395 | new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", | ||
396 | 0f, | ||
397 | (s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, | ||
398 | (s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; }, | ||
399 | (s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ), | ||
400 | new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", | ||
401 | ConfigurationParameters.numericFalse, | ||
402 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
403 | (s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; }, | ||
404 | (s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ), | ||
405 | new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", | ||
406 | ConfigurationParameters.numericFalse, | ||
407 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
408 | (s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; }, | ||
409 | (s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ), | ||
410 | new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", | ||
411 | ConfigurationParameters.numericTrue, | ||
412 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
413 | (s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; }, | ||
414 | (s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ), | ||
415 | new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", | ||
416 | ConfigurationParameters.numericTrue, | ||
417 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
418 | (s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; }, | ||
419 | (s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ), | ||
420 | new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching", | ||
421 | ConfigurationParameters.numericFalse, | ||
422 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
423 | (s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; }, | ||
424 | (s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ), | ||
425 | new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)", | ||
426 | 0f, // zero says use Bullet default | ||
427 | (s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); }, | ||
428 | (s) => { return s.UnmanagedParams[0].numberOfSolverIterations; }, | ||
429 | (s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ), | ||
430 | |||
431 | new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | ||
432 | (float)BSLinkset.LinksetImplementation.Compound, | ||
433 | (s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); }, | ||
434 | (s) => { return LinksetImplementation; }, | ||
435 | (s,p,l,v) => { LinksetImplementation = v; } ), | ||
436 | new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | ||
437 | ConfigurationParameters.numericFalse, | ||
438 | (s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
439 | (s) => { return LinkConstraintUseFrameOffset; }, | ||
440 | (s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ), | ||
441 | new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", | ||
442 | ConfigurationParameters.numericTrue, | ||
443 | (s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
444 | (s) => { return LinkConstraintEnableTransMotor; }, | ||
445 | (s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ), | ||
446 | new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", | ||
447 | 5.0f, | ||
448 | (s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); }, | ||
449 | (s) => { return LinkConstraintTransMotorMaxVel; }, | ||
450 | (s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ), | ||
451 | new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", | ||
452 | 0.1f, | ||
453 | (s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, | ||
454 | (s) => { return LinkConstraintTransMotorMaxForce; }, | ||
455 | (s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ), | ||
456 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | ||
457 | 0.1f, | ||
458 | (s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); }, | ||
459 | (s) => { return LinkConstraintCFM; }, | ||
460 | (s,p,l,v) => { LinkConstraintCFM = v; } ), | ||
461 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | ||
462 | 0.1f, | ||
463 | (s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); }, | ||
464 | (s) => { return LinkConstraintERP; }, | ||
465 | (s,p,l,v) => { LinkConstraintERP = v; } ), | ||
466 | new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", | ||
467 | 40, | ||
468 | (s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); }, | ||
469 | (s) => { return LinkConstraintSolverIterations; }, | ||
470 | (s,p,l,v) => { LinkConstraintSolverIterations = v; } ), | ||
471 | |||
472 | new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)", | ||
473 | 0f, | ||
474 | (s,cf,p,v) => { s.UnmanagedParams[0].physicsLoggingFrames = cf.GetInt(p, (int)v); }, | ||
475 | (s) => { return (float)s.UnmanagedParams[0].physicsLoggingFrames; }, | ||
476 | (s,p,l,v) => { s.UnmanagedParams[0].physicsLoggingFrames = (int)v; } ), | ||
477 | }; | ||
478 | |||
479 | // Convert a boolean to our numeric true and false values | ||
480 | public static float NumericBool(bool b) | ||
481 | { | ||
482 | return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse); | ||
483 | } | ||
484 | |||
485 | // Convert numeric true and false values to a boolean | ||
486 | public static bool BoolNumeric(float b) | ||
487 | { | ||
488 | return (b == ConfigurationParameters.numericTrue ? true : false); | ||
489 | } | ||
490 | |||
491 | // Search through the parameter definitions and return the matching | ||
492 | // ParameterDefn structure. | ||
493 | // Case does not matter as names are compared after converting to lower case. | ||
494 | // Returns 'false' if the parameter is not found. | ||
495 | internal static bool TryGetParameter(string paramName, out ParameterDefn defn) | ||
496 | { | ||
497 | bool ret = false; | ||
498 | ParameterDefn foundDefn = new ParameterDefn(); | ||
499 | string pName = paramName.ToLower(); | ||
500 | |||
501 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
502 | { | ||
503 | if (pName == parm.name.ToLower()) | ||
504 | { | ||
505 | foundDefn = parm; | ||
506 | ret = true; | ||
507 | break; | ||
508 | } | ||
509 | } | ||
510 | defn = foundDefn; | ||
511 | return ret; | ||
512 | } | ||
513 | |||
514 | // Pass through the settable parameters and set the default values | ||
515 | internal static void SetParameterDefaultValues(BSScene physicsScene) | ||
516 | { | ||
517 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
518 | { | ||
519 | parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue); | ||
520 | } | ||
521 | } | ||
522 | |||
523 | // Get user set values out of the ini file. | ||
524 | internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg) | ||
525 | { | ||
526 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
527 | { | ||
528 | parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue); | ||
529 | } | ||
530 | } | ||
531 | |||
532 | internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; | ||
533 | |||
534 | // This creates an array in the correct format for returning the list of | ||
535 | // parameters. This is used by the 'list' option of the 'physics' command. | ||
536 | internal static void BuildParameterTable() | ||
537 | { | ||
538 | if (SettableParameters.Length < ParameterDefinitions.Length) | ||
539 | { | ||
540 | List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); | ||
541 | for (int ii = 0; ii < ParameterDefinitions.Length; ii++) | ||
542 | { | ||
543 | ParameterDefn pd = ParameterDefinitions[ii]; | ||
544 | entries.Add(new PhysParameterEntry(pd.name, pd.desc)); | ||
545 | } | ||
546 | |||
547 | // make the list in alphabetical order for estetic reasons | ||
548 | entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2) | ||
549 | { | ||
550 | return ppe1.name.CompareTo(ppe2.name); | ||
551 | }); | ||
552 | |||
553 | SettableParameters = entries.ToArray(); | ||
554 | } | ||
555 | } | ||
556 | |||
557 | |||
558 | } | ||
559 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs new file mode 100644 index 0000000..689da7f --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs | |||
@@ -0,0 +1,346 @@ | |||
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.BulletSNPlugin | ||
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 two (and certainly the last one) should be referenced only 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 | public abstract class BSPhysObject : PhysicsActor | ||
59 | { | ||
60 | protected BSPhysObject() | ||
61 | { | ||
62 | } | ||
63 | protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) | ||
64 | { | ||
65 | PhysicsScene = parentScene; | ||
66 | LocalID = localID; | ||
67 | PhysObjectName = name; | ||
68 | TypeName = typeName; | ||
69 | |||
70 | Linkset = BSLinkset.Factory(PhysicsScene, this); | ||
71 | LastAssetBuildFailed = false; | ||
72 | |||
73 | // Default material type | ||
74 | Material = MaterialAttributes.Material.Wood; | ||
75 | |||
76 | CollisionCollection = new CollisionEventUpdate(); | ||
77 | SubscribedEventsMs = 0; | ||
78 | CollidingStep = 0; | ||
79 | CollidingGroundStep = 0; | ||
80 | } | ||
81 | |||
82 | // Tell the object to clean up. | ||
83 | public virtual void Destroy() | ||
84 | { | ||
85 | UnRegisterAllPreStepActions(); | ||
86 | } | ||
87 | |||
88 | public BSScene PhysicsScene { get; protected set; } | ||
89 | // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor | ||
90 | public string PhysObjectName { get; protected set; } | ||
91 | public string TypeName { get; protected set; } | ||
92 | |||
93 | public BSLinkset Linkset { get; set; } | ||
94 | public BSLinksetInfo LinksetInfo { get; set; } | ||
95 | |||
96 | // Return the object mass without calculating it or having side effects | ||
97 | public abstract float RawMass { get; } | ||
98 | // Set the raw mass but also update physical mass properties (inertia, ...) | ||
99 | // 'inWorld' true if the object has already been added to the dynamic world. | ||
100 | public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld); | ||
101 | |||
102 | // The last value calculated for the prim's inertia | ||
103 | public OMV.Vector3 Inertia { get; set; } | ||
104 | |||
105 | // Reference to the physical body (btCollisionObject) of this object | ||
106 | public BulletBody PhysBody; | ||
107 | // Reference to the physical shape (btCollisionShape) of this object | ||
108 | public BulletShape PhysShape; | ||
109 | |||
110 | // 'true' if the mesh's underlying asset failed to build. | ||
111 | // This will keep us from looping after the first time the build failed. | ||
112 | public bool LastAssetBuildFailed { get; set; } | ||
113 | |||
114 | // The objects base shape information. Null if not a prim type shape. | ||
115 | public PrimitiveBaseShape BaseShape { get; protected set; } | ||
116 | // Some types of objects have preferred physical representations. | ||
117 | // Returns SHAPE_UNKNOWN if there is no preference. | ||
118 | public virtual BSPhysicsShapeType PreferredPhysicalShape | ||
119 | { | ||
120 | get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } | ||
121 | } | ||
122 | |||
123 | // When the physical properties are updated, an EntityProperty holds the update values. | ||
124 | // Keep the current and last EntityProperties to enable computation of differences | ||
125 | // between the current update and the previous values. | ||
126 | public EntityProperties CurrentEntityProperties { get; set; } | ||
127 | public EntityProperties LastEntityProperties { get; set; } | ||
128 | |||
129 | public virtual OMV.Vector3 Scale { get; set; } | ||
130 | public abstract bool IsSolid { get; } | ||
131 | public abstract bool IsStatic { get; } | ||
132 | |||
133 | // Materialness | ||
134 | public MaterialAttributes.Material Material { get; private set; } | ||
135 | public override void SetMaterial(int material) | ||
136 | { | ||
137 | Material = (MaterialAttributes.Material)material; | ||
138 | } | ||
139 | |||
140 | // Stop all physical motion. | ||
141 | public abstract void ZeroMotion(bool inTaintTime); | ||
142 | public abstract void ZeroAngularMotion(bool inTaintTime); | ||
143 | |||
144 | // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured. | ||
145 | public virtual void StepVehicle(float timeStep) { } | ||
146 | |||
147 | // Update the physical location and motion of the object. Called with data from Bullet. | ||
148 | public abstract void UpdateProperties(EntityProperties entprop); | ||
149 | |||
150 | public abstract OMV.Vector3 RawPosition { get; set; } | ||
151 | public abstract OMV.Vector3 ForcePosition { get; set; } | ||
152 | |||
153 | public abstract OMV.Quaternion RawOrientation { get; set; } | ||
154 | public abstract OMV.Quaternion ForceOrientation { get; set; } | ||
155 | |||
156 | // The system is telling us the velocity it wants to move at. | ||
157 | // protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor | ||
158 | public override OMV.Vector3 TargetVelocity | ||
159 | { | ||
160 | get { return m_targetVelocity; } | ||
161 | set | ||
162 | { | ||
163 | m_targetVelocity = value; | ||
164 | Velocity = value; | ||
165 | } | ||
166 | } | ||
167 | public abstract OMV.Vector3 ForceVelocity { get; set; } | ||
168 | |||
169 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } | ||
170 | |||
171 | public abstract float ForceBuoyancy { get; set; } | ||
172 | |||
173 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } | ||
174 | |||
175 | #region Collisions | ||
176 | |||
177 | // Requested number of milliseconds between collision events. Zero means disabled. | ||
178 | protected int SubscribedEventsMs { get; set; } | ||
179 | // Given subscription, the time that a collision may be passed up | ||
180 | protected int NextCollisionOkTime { get; set; } | ||
181 | // The simulation step that last had a collision | ||
182 | protected long CollidingStep { get; set; } | ||
183 | // The simulation step that last had a collision with the ground | ||
184 | protected long CollidingGroundStep { get; set; } | ||
185 | // The collision flags we think are set in Bullet | ||
186 | protected CollisionFlags CurrentCollisionFlags { get; set; } | ||
187 | |||
188 | // The collisions that have been collected this tick | ||
189 | protected CollisionEventUpdate CollisionCollection; | ||
190 | |||
191 | // The simulation step is telling this object about a collision. | ||
192 | // Return 'true' if a collision was processed and should be sent up. | ||
193 | // Called at taint time from within the Step() function | ||
194 | public virtual bool Collide(uint collidingWith, BSPhysObject collidee, | ||
195 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | ||
196 | { | ||
197 | bool ret = false; | ||
198 | |||
199 | // The following lines make IsColliding() and IsCollidingGround() work | ||
200 | CollidingStep = PhysicsScene.SimulationStep; | ||
201 | if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) | ||
202 | { | ||
203 | CollidingGroundStep = PhysicsScene.SimulationStep; | ||
204 | } | ||
205 | |||
206 | // prims in the same linkset cannot collide with each other | ||
207 | if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID)) | ||
208 | { | ||
209 | return ret; | ||
210 | } | ||
211 | |||
212 | // if someone has subscribed for collision events.... | ||
213 | if (SubscribedEvents()) { | ||
214 | CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | ||
215 | DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", | ||
216 | LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth); | ||
217 | |||
218 | ret = true; | ||
219 | } | ||
220 | return ret; | ||
221 | } | ||
222 | |||
223 | // Send the collected collisions into the simulator. | ||
224 | // Called at taint time from within the Step() function thus no locking problems | ||
225 | // with CollisionCollection and ObjectsWithNoMoreCollisions. | ||
226 | // Return 'true' if there were some actual collisions passed up | ||
227 | public virtual bool SendCollisions() | ||
228 | { | ||
229 | bool ret = true; | ||
230 | // If the 'no collision' call, force it to happen right now so quick collision_end | ||
231 | bool force = (CollisionCollection.Count == 0); | ||
232 | |||
233 | // throttle the collisions to the number of milliseconds specified in the subscription | ||
234 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) | ||
235 | { | ||
236 | NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs; | ||
237 | |||
238 | // We are called if we previously had collisions. If there are no collisions | ||
239 | // this time, send up one last empty event so OpenSim can sense collision end. | ||
240 | if (CollisionCollection.Count == 0) | ||
241 | { | ||
242 | // If I have no collisions this time, remove me from the list of objects with collisions. | ||
243 | ret = false; | ||
244 | } | ||
245 | |||
246 | // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); | ||
247 | base.SendCollisionUpdate(CollisionCollection); | ||
248 | |||
249 | // The CollisionCollection instance is passed around in the simulator. | ||
250 | // Make sure we don't have a handle to that one and that a new one is used for next time. | ||
251 | // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, | ||
252 | // a race condition is created for the other users of this instance. | ||
253 | CollisionCollection = new CollisionEventUpdate(); | ||
254 | } | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | // Subscribe for collision events. | ||
259 | // Parameter is the millisecond rate the caller wishes collision events to occur. | ||
260 | public override void SubscribeEvents(int ms) { | ||
261 | // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms); | ||
262 | SubscribedEventsMs = ms; | ||
263 | if (ms > 0) | ||
264 | { | ||
265 | // make sure first collision happens | ||
266 | NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); | ||
267 | |||
268 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() | ||
269 | { | ||
270 | if (PhysBody.HasPhysicalBody) | ||
271 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
272 | }); | ||
273 | } | ||
274 | else | ||
275 | { | ||
276 | // Subscribing for zero or less is the same as unsubscribing | ||
277 | UnSubscribeEvents(); | ||
278 | } | ||
279 | } | ||
280 | public override void UnSubscribeEvents() { | ||
281 | // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); | ||
282 | SubscribedEventsMs = 0; | ||
283 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() | ||
284 | { | ||
285 | // Make sure there is a body there because sometimes destruction happens in an un-ideal order. | ||
286 | if (PhysBody.HasPhysicalBody) | ||
287 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
288 | }); | ||
289 | } | ||
290 | // Return 'true' if the simulator wants collision events | ||
291 | public override bool SubscribedEvents() { | ||
292 | return (SubscribedEventsMs > 0); | ||
293 | } | ||
294 | |||
295 | #endregion // Collisions | ||
296 | |||
297 | #region Per Simulation Step actions | ||
298 | // There are some actions that must be performed for a physical object before each simulation step. | ||
299 | // These actions are optional so, rather than scanning all the physical objects and asking them | ||
300 | // if they have anything to do, a physical object registers for an event call before the step is performed. | ||
301 | // This bookkeeping makes it easy to add, remove and clean up after all these registrations. | ||
302 | private Dictionary<string, BSScene.PreStepAction> RegisteredActions = new Dictionary<string, BSScene.PreStepAction>(); | ||
303 | protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn) | ||
304 | { | ||
305 | string identifier = op + "-" + id.ToString(); | ||
306 | RegisteredActions[identifier] = actn; | ||
307 | PhysicsScene.BeforeStep += actn; | ||
308 | DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier); | ||
309 | } | ||
310 | |||
311 | // Unregister a pre step action. Safe to call if the action has not been registered. | ||
312 | protected void UnRegisterPreStepAction(string op, uint id) | ||
313 | { | ||
314 | string identifier = op + "-" + id.ToString(); | ||
315 | bool removed = false; | ||
316 | if (RegisteredActions.ContainsKey(identifier)) | ||
317 | { | ||
318 | PhysicsScene.BeforeStep -= RegisteredActions[identifier]; | ||
319 | RegisteredActions.Remove(identifier); | ||
320 | removed = true; | ||
321 | } | ||
322 | DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed); | ||
323 | } | ||
324 | |||
325 | protected void UnRegisterAllPreStepActions() | ||
326 | { | ||
327 | foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredActions) | ||
328 | { | ||
329 | PhysicsScene.BeforeStep -= kvp.Value; | ||
330 | } | ||
331 | RegisteredActions.Clear(); | ||
332 | DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID); | ||
333 | } | ||
334 | |||
335 | |||
336 | #endregion // Per Simulation Step actions | ||
337 | |||
338 | // High performance detailed logging routine used by the physical objects. | ||
339 | protected void DetailLog(string msg, params Object[] args) | ||
340 | { | ||
341 | if (PhysicsScene.PhysicsLogging.Enabled) | ||
342 | PhysicsScene.DetailLog(msg, args); | ||
343 | } | ||
344 | |||
345 | } | ||
346 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs new file mode 100644 index 0000000..75963ee --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs | |||
@@ -0,0 +1,81 @@ | |||
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.BulletSNPlugin | ||
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 | |||
63 | // If not Windows, loading is performed by the | ||
64 | // Mono loader as specified in | ||
65 | // "bin/Physics/OpenSim.Region.Physics.BulletSNPlugin.dll.config". | ||
66 | |||
67 | _mScene = new BSScene(sceneIdentifier); | ||
68 | } | ||
69 | return (_mScene); | ||
70 | } | ||
71 | |||
72 | public string GetName() | ||
73 | { | ||
74 | return ("BulletSimN"); | ||
75 | } | ||
76 | |||
77 | public void Dispose() | ||
78 | { | ||
79 | } | ||
80 | } | ||
81 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs new file mode 100644 index 0000000..aadb5b2 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs | |||
@@ -0,0 +1,1494 @@ | |||
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 | |||
38 | namespace OpenSim.Region.Physics.BulletSNPlugin | ||
39 | { | ||
40 | |||
41 | [Serializable] | ||
42 | public sealed class BSPrim : BSPhysObject | ||
43 | { | ||
44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
45 | private static readonly string LogHeader = "[BULLETS PRIM]"; | ||
46 | |||
47 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. | ||
48 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user | ||
49 | |||
50 | private bool _grabbed; | ||
51 | private bool _isSelected; | ||
52 | private bool _isVolumeDetect; | ||
53 | private OMV.Vector3 _position; | ||
54 | private float _mass; // the mass of this object | ||
55 | private float _density; | ||
56 | private OMV.Vector3 _force; | ||
57 | private OMV.Vector3 _velocity; | ||
58 | private OMV.Vector3 _torque; | ||
59 | private float _collisionScore; | ||
60 | private OMV.Vector3 _acceleration; | ||
61 | private OMV.Quaternion _orientation; | ||
62 | private int _physicsActorType; | ||
63 | private bool _isPhysical; | ||
64 | private bool _flying; | ||
65 | private float _friction; | ||
66 | private float _restitution; | ||
67 | private bool _setAlwaysRun; | ||
68 | private bool _throttleUpdates; | ||
69 | private bool _isColliding; | ||
70 | private bool _collidingGround; | ||
71 | private bool _collidingObj; | ||
72 | private bool _floatOnWater; | ||
73 | private OMV.Vector3 _rotationalVelocity; | ||
74 | private bool _kinematic; | ||
75 | private float _buoyancy; | ||
76 | |||
77 | private BSDynamics _vehicle; | ||
78 | |||
79 | private OMV.Vector3 _PIDTarget; | ||
80 | private bool _usePID; | ||
81 | private float _PIDTau; | ||
82 | private bool _useHoverPID; | ||
83 | private float _PIDHoverHeight; | ||
84 | private PIDHoverType _PIDHoverType; | ||
85 | private float _PIDHoverTao; | ||
86 | |||
87 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | ||
88 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | ||
89 | : base(parent_scene, localID, primName, "BSPrim") | ||
90 | { | ||
91 | // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); | ||
92 | _physicsActorType = (int)ActorTypes.Prim; | ||
93 | _position = pos; | ||
94 | _size = size; | ||
95 | Scale = size; // prims are the size the user wants them to be (different for BSCharactes). | ||
96 | _orientation = rotation; | ||
97 | _buoyancy = 1f; | ||
98 | _velocity = OMV.Vector3.Zero; | ||
99 | _rotationalVelocity = OMV.Vector3.Zero; | ||
100 | BaseShape = pbs; | ||
101 | _isPhysical = pisPhysical; | ||
102 | _isVolumeDetect = false; | ||
103 | |||
104 | // Someday set default attributes based on the material but, for now, we don't know the prim material yet. | ||
105 | // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical); | ||
106 | _density = PhysicsScene.Params.defaultDensity; | ||
107 | _friction = PhysicsScene.Params.defaultFriction; | ||
108 | _restitution = PhysicsScene.Params.defaultRestitution; | ||
109 | |||
110 | _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness | ||
111 | |||
112 | _mass = CalculateMass(); | ||
113 | |||
114 | Linkset.Refresh(this); | ||
115 | |||
116 | DetailLog("{0},BSPrim.constructor,call", LocalID); | ||
117 | // do the actual object creation at taint time | ||
118 | PhysicsScene.TaintedObject("BSPrim.create", delegate() | ||
119 | { | ||
120 | CreateGeomAndObject(true); | ||
121 | |||
122 | CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr); | ||
123 | }); | ||
124 | } | ||
125 | |||
126 | // called when this prim is being destroyed and we should free all the resources | ||
127 | public override void Destroy() | ||
128 | { | ||
129 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); | ||
130 | base.Destroy(); | ||
131 | |||
132 | // Undo any links between me and any other object | ||
133 | BSPhysObject parentBefore = Linkset.LinksetRoot; | ||
134 | int childrenBefore = Linkset.NumberOfChildren; | ||
135 | |||
136 | Linkset = Linkset.RemoveMeFromLinkset(this); | ||
137 | |||
138 | DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}", | ||
139 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
140 | |||
141 | // Undo any vehicle properties | ||
142 | this.VehicleType = (int)Vehicle.TYPE_NONE; | ||
143 | |||
144 | PhysicsScene.TaintedObject("BSPrim.destroy", delegate() | ||
145 | { | ||
146 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); | ||
147 | // If there are physical body and shape, release my use of same. | ||
148 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | ||
149 | PhysBody.Clear(); | ||
150 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | ||
151 | PhysShape.Clear(); | ||
152 | }); | ||
153 | } | ||
154 | |||
155 | // No one uses this property. | ||
156 | public override bool Stopped { | ||
157 | get { return false; } | ||
158 | } | ||
159 | public override OMV.Vector3 Size { | ||
160 | get { return _size; } | ||
161 | set { | ||
162 | // We presume the scale and size are the same. If scale must be changed for | ||
163 | // the physical shape, that is done when the geometry is built. | ||
164 | _size = value; | ||
165 | Scale = _size; | ||
166 | ForceBodyShapeRebuild(false); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | public override PrimitiveBaseShape Shape { | ||
171 | set { | ||
172 | BaseShape = value; | ||
173 | ForceBodyShapeRebuild(false); | ||
174 | } | ||
175 | } | ||
176 | // Whatever the linkset wants is what I want. | ||
177 | public override BSPhysicsShapeType PreferredPhysicalShape | ||
178 | { get { return Linkset.PreferredPhysicalShape(this); } } | ||
179 | |||
180 | public override bool ForceBodyShapeRebuild(bool inTaintTime) | ||
181 | { | ||
182 | LastAssetBuildFailed = false; | ||
183 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() | ||
184 | { | ||
185 | _mass = CalculateMass(); // changing the shape changes the mass | ||
186 | CreateGeomAndObject(true); | ||
187 | }); | ||
188 | return true; | ||
189 | } | ||
190 | public override bool Grabbed { | ||
191 | set { _grabbed = value; | ||
192 | } | ||
193 | } | ||
194 | public override bool Selected { | ||
195 | set | ||
196 | { | ||
197 | if (value != _isSelected) | ||
198 | { | ||
199 | _isSelected = value; | ||
200 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() | ||
201 | { | ||
202 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | ||
203 | SetObjectDynamic(false); | ||
204 | }); | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | public override void CrossingFailure() { return; } | ||
209 | |||
210 | // link me to the specified parent | ||
211 | public override void link(PhysicsActor obj) { | ||
212 | BSPrim parent = obj as BSPrim; | ||
213 | if (parent != null) | ||
214 | { | ||
215 | BSPhysObject parentBefore = Linkset.LinksetRoot; | ||
216 | int childrenBefore = Linkset.NumberOfChildren; | ||
217 | |||
218 | Linkset = parent.Linkset.AddMeToLinkset(this); | ||
219 | |||
220 | DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", | ||
221 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
222 | } | ||
223 | return; | ||
224 | } | ||
225 | |||
226 | // delink me from my linkset | ||
227 | public override void delink() { | ||
228 | // TODO: decide if this parent checking needs to happen at taint time | ||
229 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen | ||
230 | |||
231 | BSPhysObject parentBefore = Linkset.LinksetRoot; | ||
232 | int childrenBefore = Linkset.NumberOfChildren; | ||
233 | |||
234 | Linkset = Linkset.RemoveMeFromLinkset(this); | ||
235 | |||
236 | DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", | ||
237 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
238 | return; | ||
239 | } | ||
240 | |||
241 | // Set motion values to zero. | ||
242 | // Do it to the properties so the values get set in the physics engine. | ||
243 | // Push the setting of the values to the viewer. | ||
244 | // Called at taint time! | ||
245 | public override void ZeroMotion(bool inTaintTime) | ||
246 | { | ||
247 | _velocity = OMV.Vector3.Zero; | ||
248 | _acceleration = OMV.Vector3.Zero; | ||
249 | _rotationalVelocity = OMV.Vector3.Zero; | ||
250 | |||
251 | // Zero some other properties in the physics engine | ||
252 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | ||
253 | { | ||
254 | if (PhysBody.HasPhysicalBody) | ||
255 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | ||
256 | }); | ||
257 | } | ||
258 | public override void ZeroAngularMotion(bool inTaintTime) | ||
259 | { | ||
260 | _rotationalVelocity = OMV.Vector3.Zero; | ||
261 | // Zero some other properties in the physics engine | ||
262 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | ||
263 | { | ||
264 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); | ||
265 | if (PhysBody.HasPhysicalBody) | ||
266 | { | ||
267 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||
268 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||
269 | } | ||
270 | }); | ||
271 | } | ||
272 | |||
273 | public override void LockAngularMotion(OMV.Vector3 axis) | ||
274 | { | ||
275 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); | ||
276 | return; | ||
277 | } | ||
278 | |||
279 | public override OMV.Vector3 RawPosition | ||
280 | { | ||
281 | get { return _position; } | ||
282 | set { _position = value; } | ||
283 | } | ||
284 | public override OMV.Vector3 Position { | ||
285 | get { | ||
286 | /* NOTE: this refetch is not necessary. The simulator knows about linkset children | ||
287 | * and does not fetch this position info for children. Thus this is commented out. | ||
288 | // child prims move around based on their parent. Need to get the latest location | ||
289 | if (!Linkset.IsRoot(this)) | ||
290 | _position = Linkset.PositionGet(this); | ||
291 | */ | ||
292 | |||
293 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. | ||
294 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | ||
295 | return _position; | ||
296 | } | ||
297 | set { | ||
298 | // If the position must be forced into the physics engine, use ForcePosition. | ||
299 | // All positions are given in world positions. | ||
300 | if (_position == value) | ||
301 | { | ||
302 | DetailLog("{0},BSPrim.setPosition,taint,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation); | ||
303 | return; | ||
304 | } | ||
305 | _position = value; | ||
306 | PositionSanityCheck(false); | ||
307 | |||
308 | // A linkset might need to know if a component information changed. | ||
309 | Linkset.UpdateProperties(this, false); | ||
310 | |||
311 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() | ||
312 | { | ||
313 | DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
314 | ForcePosition = _position; | ||
315 | }); | ||
316 | } | ||
317 | } | ||
318 | public override OMV.Vector3 ForcePosition { | ||
319 | get { | ||
320 | _position = BulletSimAPI.GetPosition2(PhysBody.ptr); | ||
321 | return _position; | ||
322 | } | ||
323 | set { | ||
324 | _position = value; | ||
325 | if (PhysBody.HasPhysicalBody) | ||
326 | { | ||
327 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
328 | ActivateIfPhysical(false); | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | |||
333 | // Check that the current position is sane and, if not, modify the position to make it so. | ||
334 | // Check for being below terrain and being out of bounds. | ||
335 | // Returns 'true' of the position was made sane by some action. | ||
336 | private bool PositionSanityCheck(bool inTaintTime) | ||
337 | { | ||
338 | bool ret = false; | ||
339 | |||
340 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) | ||
341 | { | ||
342 | // The physical object is out of the known/simulated area. | ||
343 | // Upper levels of code will handle the transition to other areas so, for | ||
344 | // the time, we just ignore the position. | ||
345 | return ret; | ||
346 | } | ||
347 | |||
348 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | ||
349 | OMV.Vector3 upForce = OMV.Vector3.Zero; | ||
350 | if (RawPosition.Z < terrainHeight) | ||
351 | { | ||
352 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | ||
353 | float targetHeight = terrainHeight + (Size.Z / 2f); | ||
354 | // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. | ||
355 | upForce.Z = (terrainHeight - RawPosition.Z) * 1f; | ||
356 | ret = true; | ||
357 | } | ||
358 | |||
359 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | ||
360 | { | ||
361 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); | ||
362 | // TODO: a floating motor so object will bob in the water | ||
363 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) | ||
364 | { | ||
365 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. | ||
366 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; | ||
367 | ret = true; | ||
368 | } | ||
369 | } | ||
370 | |||
371 | // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. | ||
372 | // TODO: This should be intergrated with a geneal physics action mechanism. | ||
373 | // TODO: This should be moderated with PID'ness. | ||
374 | if (ret) | ||
375 | { | ||
376 | // Apply upforce and overcome gravity. | ||
377 | OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; | ||
378 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); | ||
379 | AddForce(correctionForce, false, inTaintTime); | ||
380 | } | ||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | // Return the effective mass of the object. | ||
385 | // The definition of this call is to return the mass of the prim. | ||
386 | // If the simulator cares about the mass of the linkset, it will sum it itself. | ||
387 | public override float Mass | ||
388 | { | ||
389 | get | ||
390 | { | ||
391 | return _mass; | ||
392 | } | ||
393 | } | ||
394 | |||
395 | // used when we only want this prim's mass and not the linkset thing | ||
396 | public override float RawMass { | ||
397 | get { return _mass; } | ||
398 | } | ||
399 | // Set the physical mass to the passed mass. | ||
400 | // Note that this does not change _mass! | ||
401 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) | ||
402 | { | ||
403 | if (PhysBody.HasPhysicalBody) | ||
404 | { | ||
405 | if (IsStatic) | ||
406 | { | ||
407 | Inertia = OMV.Vector3.Zero; | ||
408 | BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia); | ||
409 | BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); | ||
410 | } | ||
411 | else | ||
412 | { | ||
413 | if (inWorld) | ||
414 | { | ||
415 | // Changing interesting properties doesn't change proxy and collision cache | ||
416 | // information. The Bullet solution is to re-add the object to the world | ||
417 | // after parameters are changed. | ||
418 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | ||
419 | } | ||
420 | |||
421 | Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); | ||
422 | BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia); | ||
423 | BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); | ||
424 | |||
425 | // center of mass is at the zero of the object | ||
426 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation); | ||
427 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},inWorld={3}", LocalID, physMass, Inertia, inWorld); | ||
428 | |||
429 | if (inWorld) | ||
430 | { | ||
431 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr,_position,_orientation); | ||
432 | } | ||
433 | |||
434 | // Must set gravity after it has been added to the world because, for unknown reasons, | ||
435 | // adding the object resets the object's gravity to world gravity | ||
436 | OMV.Vector3 grav = PhysicsScene.DefaultGravity * (1f - Buoyancy); | ||
437 | BulletSimAPI.SetGravity2(PhysBody.ptr, grav); | ||
438 | |||
439 | } | ||
440 | } | ||
441 | } | ||
442 | |||
443 | // Is this used? | ||
444 | public override OMV.Vector3 CenterOfMass | ||
445 | { | ||
446 | get { return Linkset.CenterOfMass; } | ||
447 | } | ||
448 | |||
449 | // Is this used? | ||
450 | public override OMV.Vector3 GeometricCenter | ||
451 | { | ||
452 | get { return Linkset.GeometricCenter; } | ||
453 | } | ||
454 | |||
455 | public override OMV.Vector3 Force { | ||
456 | get { return _force; } | ||
457 | set { | ||
458 | _force = value; | ||
459 | if (_force != OMV.Vector3.Zero) | ||
460 | { | ||
461 | // If the force is non-zero, it must be reapplied each tick because | ||
462 | // Bullet clears the forces applied last frame. | ||
463 | RegisterPreStepAction("BSPrim.setForce", LocalID, | ||
464 | delegate(float timeStep) | ||
465 | { | ||
466 | DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); | ||
467 | if (PhysBody.HasPhysicalBody) | ||
468 | { | ||
469 | BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, _force); | ||
470 | ActivateIfPhysical(false); | ||
471 | } | ||
472 | } | ||
473 | ); | ||
474 | } | ||
475 | else | ||
476 | { | ||
477 | UnRegisterPreStepAction("BSPrim.setForce", LocalID); | ||
478 | } | ||
479 | } | ||
480 | } | ||
481 | |||
482 | public override int VehicleType { | ||
483 | get { | ||
484 | return (int)_vehicle.Type; // if we are a vehicle, return that type | ||
485 | } | ||
486 | set { | ||
487 | Vehicle type = (Vehicle)value; | ||
488 | |||
489 | PhysicsScene.TaintedObject("setVehicleType", delegate() | ||
490 | { | ||
491 | // Done at taint time so we're sure the physics engine is not using the variables | ||
492 | // Vehicle code changes the parameters for this vehicle type. | ||
493 | _vehicle.ProcessTypeChange(type); | ||
494 | ActivateIfPhysical(false); | ||
495 | |||
496 | // If an active vehicle, register the vehicle code to be called before each step | ||
497 | if (_vehicle.Type == Vehicle.TYPE_NONE) | ||
498 | UnRegisterPreStepAction("BSPrim.Vehicle", LocalID); | ||
499 | else | ||
500 | RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step); | ||
501 | }); | ||
502 | } | ||
503 | } | ||
504 | public override void VehicleFloatParam(int param, float value) | ||
505 | { | ||
506 | PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() | ||
507 | { | ||
508 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); | ||
509 | ActivateIfPhysical(false); | ||
510 | }); | ||
511 | } | ||
512 | public override void VehicleVectorParam(int param, OMV.Vector3 value) | ||
513 | { | ||
514 | PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() | ||
515 | { | ||
516 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); | ||
517 | ActivateIfPhysical(false); | ||
518 | }); | ||
519 | } | ||
520 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) | ||
521 | { | ||
522 | PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() | ||
523 | { | ||
524 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); | ||
525 | ActivateIfPhysical(false); | ||
526 | }); | ||
527 | } | ||
528 | public override void VehicleFlags(int param, bool remove) | ||
529 | { | ||
530 | PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() | ||
531 | { | ||
532 | _vehicle.ProcessVehicleFlags(param, remove); | ||
533 | }); | ||
534 | } | ||
535 | |||
536 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | ||
537 | public override void SetVolumeDetect(int param) { | ||
538 | bool newValue = (param != 0); | ||
539 | if (_isVolumeDetect != newValue) | ||
540 | { | ||
541 | _isVolumeDetect = newValue; | ||
542 | PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() | ||
543 | { | ||
544 | // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); | ||
545 | SetObjectDynamic(true); | ||
546 | }); | ||
547 | } | ||
548 | return; | ||
549 | } | ||
550 | public override OMV.Vector3 Velocity { | ||
551 | get { return _velocity; } | ||
552 | set { | ||
553 | _velocity = value; | ||
554 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() | ||
555 | { | ||
556 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); | ||
557 | ForceVelocity = _velocity; | ||
558 | }); | ||
559 | } | ||
560 | } | ||
561 | public override OMV.Vector3 ForceVelocity { | ||
562 | get { return _velocity; } | ||
563 | set { | ||
564 | PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); | ||
565 | |||
566 | _velocity = value; | ||
567 | if (PhysBody.HasPhysicalBody) | ||
568 | { | ||
569 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | ||
570 | ActivateIfPhysical(false); | ||
571 | } | ||
572 | } | ||
573 | } | ||
574 | public override OMV.Vector3 Torque { | ||
575 | get { return _torque; } | ||
576 | set { | ||
577 | _torque = value; | ||
578 | if (_torque != OMV.Vector3.Zero) | ||
579 | { | ||
580 | // If the torque is non-zero, it must be reapplied each tick because | ||
581 | // Bullet clears the forces applied last frame. | ||
582 | RegisterPreStepAction("BSPrim.setTorque", LocalID, | ||
583 | delegate(float timeStep) | ||
584 | { | ||
585 | if (PhysBody.HasPhysicalBody) | ||
586 | AddAngularForce(_torque, false, true); | ||
587 | } | ||
588 | ); | ||
589 | } | ||
590 | else | ||
591 | { | ||
592 | UnRegisterPreStepAction("BSPrim.setTorque", LocalID); | ||
593 | } | ||
594 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); | ||
595 | } | ||
596 | } | ||
597 | public override float CollisionScore { | ||
598 | get { return _collisionScore; } | ||
599 | set { _collisionScore = value; | ||
600 | } | ||
601 | } | ||
602 | public override OMV.Vector3 Acceleration { | ||
603 | get { return _acceleration; } | ||
604 | set { _acceleration = value; } | ||
605 | } | ||
606 | public override OMV.Quaternion RawOrientation | ||
607 | { | ||
608 | get { return _orientation; } | ||
609 | set { _orientation = value; } | ||
610 | } | ||
611 | public override OMV.Quaternion Orientation { | ||
612 | get { | ||
613 | /* NOTE: this refetch is not necessary. The simulator knows about linkset children | ||
614 | * and does not fetch this position info for children. Thus this is commented out. | ||
615 | // Children move around because tied to parent. Get a fresh value. | ||
616 | if (!Linkset.IsRoot(this)) | ||
617 | { | ||
618 | _orientation = Linkset.OrientationGet(this); | ||
619 | } | ||
620 | */ | ||
621 | return _orientation; | ||
622 | } | ||
623 | set { | ||
624 | if (_orientation == value) | ||
625 | return; | ||
626 | _orientation = value; | ||
627 | |||
628 | // A linkset might need to know if a component information changed. | ||
629 | Linkset.UpdateProperties(this, false); | ||
630 | |||
631 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() | ||
632 | { | ||
633 | if (PhysBody.HasPhysicalBody) | ||
634 | { | ||
635 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | ||
636 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
637 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
638 | } | ||
639 | }); | ||
640 | } | ||
641 | } | ||
642 | // Go directly to Bullet to get/set the value. | ||
643 | public override OMV.Quaternion ForceOrientation | ||
644 | { | ||
645 | get | ||
646 | { | ||
647 | _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); | ||
648 | return _orientation; | ||
649 | } | ||
650 | set | ||
651 | { | ||
652 | _orientation = value; | ||
653 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
654 | } | ||
655 | } | ||
656 | public override int PhysicsActorType { | ||
657 | get { return _physicsActorType; } | ||
658 | set { _physicsActorType = value; } | ||
659 | } | ||
660 | public override bool IsPhysical { | ||
661 | get { return _isPhysical; } | ||
662 | set { | ||
663 | if (_isPhysical != value) | ||
664 | { | ||
665 | _isPhysical = value; | ||
666 | PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() | ||
667 | { | ||
668 | // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); | ||
669 | SetObjectDynamic(true); | ||
670 | // whether phys-to-static or static-to-phys, the object is not moving. | ||
671 | ZeroMotion(true); | ||
672 | }); | ||
673 | } | ||
674 | } | ||
675 | } | ||
676 | |||
677 | // An object is static (does not move) if selected or not physical | ||
678 | public override bool IsStatic | ||
679 | { | ||
680 | get { return _isSelected || !IsPhysical; } | ||
681 | } | ||
682 | |||
683 | // An object is solid if it's not phantom and if it's not doing VolumeDetect | ||
684 | public override bool IsSolid | ||
685 | { | ||
686 | get { return !IsPhantom && !_isVolumeDetect; } | ||
687 | } | ||
688 | |||
689 | // Make gravity work if the object is physical and not selected | ||
690 | // Called at taint-time!! | ||
691 | private void SetObjectDynamic(bool forceRebuild) | ||
692 | { | ||
693 | // Recreate the physical object if necessary | ||
694 | CreateGeomAndObject(forceRebuild); | ||
695 | } | ||
696 | |||
697 | // Convert the simulator's physical properties into settings on BulletSim objects. | ||
698 | // There are four flags we're interested in: | ||
699 | // IsStatic: Object does not move, otherwise the object has mass and moves | ||
700 | // isSolid: other objects bounce off of this object | ||
701 | // isVolumeDetect: other objects pass through but can generate collisions | ||
702 | // collisionEvents: whether this object returns collision events | ||
703 | private void UpdatePhysicalParameters() | ||
704 | { | ||
705 | // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape); | ||
706 | |||
707 | // Mangling all the physical properties requires the object not be in the physical world. | ||
708 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). | ||
709 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | ||
710 | |||
711 | // Set up the object physicalness (does gravity and collisions move this object) | ||
712 | MakeDynamic(IsStatic); | ||
713 | |||
714 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) | ||
715 | _vehicle.Refresh(); | ||
716 | |||
717 | // Arrange for collision events if the simulator wants them | ||
718 | EnableCollisions(SubscribedEvents()); | ||
719 | |||
720 | // Make solid or not (do things bounce off or pass through this object). | ||
721 | MakeSolid(IsSolid); | ||
722 | |||
723 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr, _position, _orientation); | ||
724 | |||
725 | // Rebuild its shape | ||
726 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | ||
727 | |||
728 | // Collision filter can be set only when the object is in the world | ||
729 | PhysBody.ApplyCollisionMask(); | ||
730 | |||
731 | // Recompute any linkset parameters. | ||
732 | // When going from non-physical to physical, this re-enables the constraints that | ||
733 | // had been automatically disabled when the mass was set to zero. | ||
734 | // For compound based linksets, this enables and disables interactions of the children. | ||
735 | Linkset.Refresh(this); | ||
736 | |||
737 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", | ||
738 | LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape); | ||
739 | } | ||
740 | |||
741 | // "Making dynamic" means changing to and from static. | ||
742 | // When static, gravity does not effect the object and it is fixed in space. | ||
743 | // When dynamic, the object can fall and be pushed by others. | ||
744 | // This is independent of its 'solidness' which controls what passes through | ||
745 | // this object and what interacts with it. | ||
746 | private void MakeDynamic(bool makeStatic) | ||
747 | { | ||
748 | if (makeStatic) | ||
749 | { | ||
750 | // Become a Bullet 'static' object type | ||
751 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
752 | // Stop all movement | ||
753 | ZeroMotion(true); | ||
754 | |||
755 | // Set various physical properties so other object interact properly | ||
756 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); | ||
757 | BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction); | ||
758 | BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution); | ||
759 | |||
760 | // Mass is zero which disables a bunch of physics stuff in Bullet | ||
761 | UpdatePhysicalMassProperties(0f, false); | ||
762 | // Set collision detection parameters | ||
763 | if (BSParam.CcdMotionThreshold > 0f) | ||
764 | { | ||
765 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold); | ||
766 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius); | ||
767 | } | ||
768 | |||
769 | // The activation state is 'disabled' so Bullet will not try to act on it. | ||
770 | // BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | ||
771 | // Start it out sleeping and physical actions could wake it up. | ||
772 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING); | ||
773 | |||
774 | // This collides like a static object | ||
775 | PhysBody.collisionType = CollisionType.Static; | ||
776 | |||
777 | // There can be special things needed for implementing linksets | ||
778 | Linkset.MakeStatic(this); | ||
779 | } | ||
780 | else | ||
781 | { | ||
782 | // Not a Bullet static object | ||
783 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
784 | |||
785 | // Set various physical properties so other object interact properly | ||
786 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true); | ||
787 | BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction); | ||
788 | BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution); | ||
789 | |||
790 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 | ||
791 | // Since this can be called multiple times, only zero forces when becoming physical | ||
792 | // BulletSimAPI.ClearAllForces2(BSBody.ptr); | ||
793 | |||
794 | // For good measure, make sure the transform is set through to the motion state | ||
795 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
796 | |||
797 | // Center of mass is at the center of the object | ||
798 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); | ||
799 | |||
800 | // A dynamic object has mass | ||
801 | UpdatePhysicalMassProperties(RawMass, false); | ||
802 | |||
803 | // Set collision detection parameters | ||
804 | if (BSParam.CcdMotionThreshold > 0f) | ||
805 | { | ||
806 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold); | ||
807 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius); | ||
808 | } | ||
809 | |||
810 | // Various values for simulation limits | ||
811 | BulletSimAPI.SetDamping2(PhysBody.ptr, BSParam.LinearDamping, BSParam.AngularDamping); | ||
812 | BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, BSParam.DeactivationTime); | ||
813 | BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); | ||
814 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold); | ||
815 | |||
816 | // This collides like an object. | ||
817 | PhysBody.collisionType = CollisionType.Dynamic; | ||
818 | |||
819 | // Force activation of the object so Bullet will act on it. | ||
820 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. | ||
821 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); | ||
822 | |||
823 | // There might be special things needed for implementing linksets. | ||
824 | Linkset.MakeDynamic(this); | ||
825 | } | ||
826 | } | ||
827 | |||
828 | // "Making solid" means that other object will not pass through this object. | ||
829 | // To make transparent, we create a Bullet ghost object. | ||
830 | // Note: This expects to be called from the UpdatePhysicalParameters() routine as | ||
831 | // the functions after this one set up the state of a possibly newly created collision body. | ||
832 | private void MakeSolid(bool makeSolid) | ||
833 | { | ||
834 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr); | ||
835 | if (makeSolid) | ||
836 | { | ||
837 | // Verify the previous code created the correct shape for this type of thing. | ||
838 | if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0) | ||
839 | { | ||
840 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); | ||
841 | } | ||
842 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
843 | } | ||
844 | else | ||
845 | { | ||
846 | if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0) | ||
847 | { | ||
848 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | ||
849 | } | ||
850 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
851 | |||
852 | // Change collision info from a static object to a ghosty collision object | ||
853 | PhysBody.collisionType = CollisionType.VolumeDetect; | ||
854 | } | ||
855 | } | ||
856 | |||
857 | // Enable physical actions. Bullet will keep sleeping non-moving physical objects so | ||
858 | // they need waking up when parameters are changed. | ||
859 | // Called in taint-time!! | ||
860 | private void ActivateIfPhysical(bool forceIt) | ||
861 | { | ||
862 | if (IsPhysical && PhysBody.HasPhysicalBody) | ||
863 | BulletSimAPI.Activate2(PhysBody.ptr, forceIt); | ||
864 | } | ||
865 | |||
866 | // Turn on or off the flag controlling whether collision events are returned to the simulator. | ||
867 | private void EnableCollisions(bool wantsCollisionEvents) | ||
868 | { | ||
869 | if (wantsCollisionEvents) | ||
870 | { | ||
871 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
872 | } | ||
873 | else | ||
874 | { | ||
875 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
876 | } | ||
877 | } | ||
878 | |||
879 | // prims don't fly | ||
880 | public override bool Flying { | ||
881 | get { return _flying; } | ||
882 | set { | ||
883 | _flying = value; | ||
884 | } | ||
885 | } | ||
886 | public override bool SetAlwaysRun { | ||
887 | get { return _setAlwaysRun; } | ||
888 | set { _setAlwaysRun = value; } | ||
889 | } | ||
890 | public override bool ThrottleUpdates { | ||
891 | get { return _throttleUpdates; } | ||
892 | set { _throttleUpdates = value; } | ||
893 | } | ||
894 | public override bool IsColliding { | ||
895 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | ||
896 | set { _isColliding = value; } | ||
897 | } | ||
898 | public override bool CollidingGround { | ||
899 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | ||
900 | set { _collidingGround = value; } | ||
901 | } | ||
902 | public override bool CollidingObj { | ||
903 | get { return _collidingObj; } | ||
904 | set { _collidingObj = value; } | ||
905 | } | ||
906 | public bool IsPhantom { | ||
907 | get { | ||
908 | // SceneObjectPart removes phantom objects from the physics scene | ||
909 | // so, although we could implement touching and such, we never | ||
910 | // are invoked as a phantom object | ||
911 | return false; | ||
912 | } | ||
913 | } | ||
914 | public override bool FloatOnWater { | ||
915 | set { | ||
916 | _floatOnWater = value; | ||
917 | PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() | ||
918 | { | ||
919 | if (_floatOnWater) | ||
920 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | ||
921 | else | ||
922 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | ||
923 | }); | ||
924 | } | ||
925 | } | ||
926 | public override OMV.Vector3 RotationalVelocity { | ||
927 | get { | ||
928 | return _rotationalVelocity; | ||
929 | } | ||
930 | set { | ||
931 | _rotationalVelocity = value; | ||
932 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); | ||
933 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() | ||
934 | { | ||
935 | DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | ||
936 | ForceRotationalVelocity = _rotationalVelocity; | ||
937 | }); | ||
938 | } | ||
939 | } | ||
940 | public override OMV.Vector3 ForceRotationalVelocity { | ||
941 | get { | ||
942 | return _rotationalVelocity; | ||
943 | } | ||
944 | set { | ||
945 | _rotationalVelocity = value; | ||
946 | if (PhysBody.HasPhysicalBody) | ||
947 | { | ||
948 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||
949 | ActivateIfPhysical(false); | ||
950 | } | ||
951 | } | ||
952 | } | ||
953 | public override bool Kinematic { | ||
954 | get { return _kinematic; } | ||
955 | set { _kinematic = value; | ||
956 | // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); | ||
957 | } | ||
958 | } | ||
959 | public override float Buoyancy { | ||
960 | get { return _buoyancy; } | ||
961 | set { | ||
962 | _buoyancy = value; | ||
963 | PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() | ||
964 | { | ||
965 | ForceBuoyancy = _buoyancy; | ||
966 | }); | ||
967 | } | ||
968 | } | ||
969 | public override float ForceBuoyancy { | ||
970 | get { return _buoyancy; } | ||
971 | set { | ||
972 | _buoyancy = value; | ||
973 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
974 | // Force the recalculation of the various inertia,etc variables in the object | ||
975 | UpdatePhysicalMassProperties(_mass, true); | ||
976 | ActivateIfPhysical(false); | ||
977 | } | ||
978 | } | ||
979 | |||
980 | // Used for MoveTo | ||
981 | public override OMV.Vector3 PIDTarget { | ||
982 | set { _PIDTarget = value; } | ||
983 | } | ||
984 | public override bool PIDActive { | ||
985 | set { _usePID = value; } | ||
986 | } | ||
987 | public override float PIDTau { | ||
988 | set { _PIDTau = value; } | ||
989 | } | ||
990 | |||
991 | // Used for llSetHoverHeight and maybe vehicle height | ||
992 | // Hover Height will override MoveTo target's Z | ||
993 | public override bool PIDHoverActive { | ||
994 | set { _useHoverPID = value; } | ||
995 | } | ||
996 | public override float PIDHoverHeight { | ||
997 | set { _PIDHoverHeight = value; } | ||
998 | } | ||
999 | public override PIDHoverType PIDHoverType { | ||
1000 | set { _PIDHoverType = value; } | ||
1001 | } | ||
1002 | public override float PIDHoverTau { | ||
1003 | set { _PIDHoverTao = value; } | ||
1004 | } | ||
1005 | |||
1006 | // For RotLookAt | ||
1007 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
1008 | public override bool APIDActive { set { return; } } | ||
1009 | public override float APIDStrength { set { return; } } | ||
1010 | public override float APIDDamping { set { return; } } | ||
1011 | |||
1012 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | ||
1013 | // Since this force is being applied in only one step, make this a force per second. | ||
1014 | OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; | ||
1015 | AddForce(addForce, pushforce, false); | ||
1016 | } | ||
1017 | // Applying a force just adds this to the total force on the object. | ||
1018 | // This added force will only last the next simulation tick. | ||
1019 | public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | ||
1020 | // for an object, doesn't matter if force is a pushforce or not | ||
1021 | if (force.IsFinite()) | ||
1022 | { | ||
1023 | float magnitude = force.Length(); | ||
1024 | if (magnitude > 20000f) | ||
1025 | { | ||
1026 | // Force has a limit | ||
1027 | force = force / magnitude * 20000f; | ||
1028 | } | ||
1029 | |||
1030 | OMV.Vector3 addForce = force; | ||
1031 | DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); | ||
1032 | |||
1033 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() | ||
1034 | { | ||
1035 | // Bullet adds this central force to the total force for this tick | ||
1036 | DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); | ||
1037 | if (PhysBody.HasPhysicalBody) | ||
1038 | { | ||
1039 | BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, addForce); | ||
1040 | ActivateIfPhysical(false); | ||
1041 | } | ||
1042 | }); | ||
1043 | } | ||
1044 | else | ||
1045 | { | ||
1046 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | ||
1047 | return; | ||
1048 | } | ||
1049 | } | ||
1050 | |||
1051 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | ||
1052 | AddAngularForce(force, pushforce, false); | ||
1053 | } | ||
1054 | public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) | ||
1055 | { | ||
1056 | if (force.IsFinite()) | ||
1057 | { | ||
1058 | OMV.Vector3 angForce = force; | ||
1059 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() | ||
1060 | { | ||
1061 | if (PhysBody.HasPhysicalBody) | ||
1062 | { | ||
1063 | BulletSimAPI.ApplyTorque2(PhysBody.ptr, angForce); | ||
1064 | ActivateIfPhysical(false); | ||
1065 | } | ||
1066 | }); | ||
1067 | } | ||
1068 | else | ||
1069 | { | ||
1070 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | ||
1071 | return; | ||
1072 | } | ||
1073 | } | ||
1074 | |||
1075 | // A torque impulse. | ||
1076 | // ApplyTorqueImpulse adds torque directly to the angularVelocity. | ||
1077 | // AddAngularForce accumulates the force and applied it to the angular velocity all at once. | ||
1078 | // Computed as: angularVelocity += impulse * inertia; | ||
1079 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) | ||
1080 | { | ||
1081 | OMV.Vector3 applyImpulse = impulse; | ||
1082 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() | ||
1083 | { | ||
1084 | if (PhysBody.HasPhysicalBody) | ||
1085 | { | ||
1086 | BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); | ||
1087 | ActivateIfPhysical(false); | ||
1088 | } | ||
1089 | }); | ||
1090 | } | ||
1091 | |||
1092 | public override void SetMomentum(OMV.Vector3 momentum) { | ||
1093 | // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); | ||
1094 | } | ||
1095 | #region Mass Calculation | ||
1096 | |||
1097 | private float CalculateMass() | ||
1098 | { | ||
1099 | float volume = _size.X * _size.Y * _size.Z; // default | ||
1100 | float tmp; | ||
1101 | |||
1102 | float returnMass = 0; | ||
1103 | float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f; | ||
1104 | float hollowVolume = hollowAmount * hollowAmount; | ||
1105 | |||
1106 | switch (BaseShape.ProfileShape) | ||
1107 | { | ||
1108 | case ProfileShape.Square: | ||
1109 | // default box | ||
1110 | |||
1111 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) | ||
1112 | { | ||
1113 | if (hollowAmount > 0.0) | ||
1114 | { | ||
1115 | switch (BaseShape.HollowShape) | ||
1116 | { | ||
1117 | case HollowShape.Square: | ||
1118 | case HollowShape.Same: | ||
1119 | break; | ||
1120 | |||
1121 | case HollowShape.Circle: | ||
1122 | |||
1123 | hollowVolume *= 0.78539816339f; | ||
1124 | break; | ||
1125 | |||
1126 | case HollowShape.Triangle: | ||
1127 | |||
1128 | hollowVolume *= (0.5f * .5f); | ||
1129 | break; | ||
1130 | |||
1131 | default: | ||
1132 | hollowVolume = 0; | ||
1133 | break; | ||
1134 | } | ||
1135 | volume *= (1.0f - hollowVolume); | ||
1136 | } | ||
1137 | } | ||
1138 | |||
1139 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) | ||
1140 | { | ||
1141 | //a tube | ||
1142 | |||
1143 | volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX); | ||
1144 | tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY); | ||
1145 | volume -= volume*tmp*tmp; | ||
1146 | |||
1147 | if (hollowAmount > 0.0) | ||
1148 | { | ||
1149 | hollowVolume *= hollowAmount; | ||
1150 | |||
1151 | switch (BaseShape.HollowShape) | ||
1152 | { | ||
1153 | case HollowShape.Square: | ||
1154 | case HollowShape.Same: | ||
1155 | break; | ||
1156 | |||
1157 | case HollowShape.Circle: | ||
1158 | hollowVolume *= 0.78539816339f;; | ||
1159 | break; | ||
1160 | |||
1161 | case HollowShape.Triangle: | ||
1162 | hollowVolume *= 0.5f * 0.5f; | ||
1163 | break; | ||
1164 | default: | ||
1165 | hollowVolume = 0; | ||
1166 | break; | ||
1167 | } | ||
1168 | volume *= (1.0f - hollowVolume); | ||
1169 | } | ||
1170 | } | ||
1171 | |||
1172 | break; | ||
1173 | |||
1174 | case ProfileShape.Circle: | ||
1175 | |||
1176 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) | ||
1177 | { | ||
1178 | volume *= 0.78539816339f; // elipse base | ||
1179 | |||
1180 | if (hollowAmount > 0.0) | ||
1181 | { | ||
1182 | switch (BaseShape.HollowShape) | ||
1183 | { | ||
1184 | case HollowShape.Same: | ||
1185 | case HollowShape.Circle: | ||
1186 | break; | ||
1187 | |||
1188 | case HollowShape.Square: | ||
1189 | hollowVolume *= 0.5f * 2.5984480504799f; | ||
1190 | break; | ||
1191 | |||
1192 | case HollowShape.Triangle: | ||
1193 | hollowVolume *= .5f * 1.27323954473516f; | ||
1194 | break; | ||
1195 | |||
1196 | default: | ||
1197 | hollowVolume = 0; | ||
1198 | break; | ||
1199 | } | ||
1200 | volume *= (1.0f - hollowVolume); | ||
1201 | } | ||
1202 | } | ||
1203 | |||
1204 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) | ||
1205 | { | ||
1206 | volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX); | ||
1207 | tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); | ||
1208 | volume *= (1.0f - tmp * tmp); | ||
1209 | |||
1210 | if (hollowAmount > 0.0) | ||
1211 | { | ||
1212 | |||
1213 | // calculate the hollow volume by it's shape compared to the prim shape | ||
1214 | hollowVolume *= hollowAmount; | ||
1215 | |||
1216 | switch (BaseShape.HollowShape) | ||
1217 | { | ||
1218 | case HollowShape.Same: | ||
1219 | case HollowShape.Circle: | ||
1220 | break; | ||
1221 | |||
1222 | case HollowShape.Square: | ||
1223 | hollowVolume *= 0.5f * 2.5984480504799f; | ||
1224 | break; | ||
1225 | |||
1226 | case HollowShape.Triangle: | ||
1227 | hollowVolume *= .5f * 1.27323954473516f; | ||
1228 | break; | ||
1229 | |||
1230 | default: | ||
1231 | hollowVolume = 0; | ||
1232 | break; | ||
1233 | } | ||
1234 | volume *= (1.0f - hollowVolume); | ||
1235 | } | ||
1236 | } | ||
1237 | break; | ||
1238 | |||
1239 | case ProfileShape.HalfCircle: | ||
1240 | if (BaseShape.PathCurve == (byte)Extrusion.Curve1) | ||
1241 | { | ||
1242 | volume *= 0.52359877559829887307710723054658f; | ||
1243 | } | ||
1244 | break; | ||
1245 | |||
1246 | case ProfileShape.EquilateralTriangle: | ||
1247 | |||
1248 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) | ||
1249 | { | ||
1250 | volume *= 0.32475953f; | ||
1251 | |||
1252 | if (hollowAmount > 0.0) | ||
1253 | { | ||
1254 | |||
1255 | // calculate the hollow volume by it's shape compared to the prim shape | ||
1256 | switch (BaseShape.HollowShape) | ||
1257 | { | ||
1258 | case HollowShape.Same: | ||
1259 | case HollowShape.Triangle: | ||
1260 | hollowVolume *= .25f; | ||
1261 | break; | ||
1262 | |||
1263 | case HollowShape.Square: | ||
1264 | hollowVolume *= 0.499849f * 3.07920140172638f; | ||
1265 | break; | ||
1266 | |||
1267 | case HollowShape.Circle: | ||
1268 | // Hollow shape is a perfect cyllinder in respect to the cube's scale | ||
1269 | // Cyllinder hollow volume calculation | ||
1270 | |||
1271 | hollowVolume *= 0.1963495f * 3.07920140172638f; | ||
1272 | break; | ||
1273 | |||
1274 | default: | ||
1275 | hollowVolume = 0; | ||
1276 | break; | ||
1277 | } | ||
1278 | volume *= (1.0f - hollowVolume); | ||
1279 | } | ||
1280 | } | ||
1281 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) | ||
1282 | { | ||
1283 | volume *= 0.32475953f; | ||
1284 | volume *= 0.01f * (float)(200 - BaseShape.PathScaleX); | ||
1285 | tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); | ||
1286 | volume *= (1.0f - tmp * tmp); | ||
1287 | |||
1288 | if (hollowAmount > 0.0) | ||
1289 | { | ||
1290 | |||
1291 | hollowVolume *= hollowAmount; | ||
1292 | |||
1293 | switch (BaseShape.HollowShape) | ||
1294 | { | ||
1295 | case HollowShape.Same: | ||
1296 | case HollowShape.Triangle: | ||
1297 | hollowVolume *= .25f; | ||
1298 | break; | ||
1299 | |||
1300 | case HollowShape.Square: | ||
1301 | hollowVolume *= 0.499849f * 3.07920140172638f; | ||
1302 | break; | ||
1303 | |||
1304 | case HollowShape.Circle: | ||
1305 | |||
1306 | hollowVolume *= 0.1963495f * 3.07920140172638f; | ||
1307 | break; | ||
1308 | |||
1309 | default: | ||
1310 | hollowVolume = 0; | ||
1311 | break; | ||
1312 | } | ||
1313 | volume *= (1.0f - hollowVolume); | ||
1314 | } | ||
1315 | } | ||
1316 | break; | ||
1317 | |||
1318 | default: | ||
1319 | break; | ||
1320 | } | ||
1321 | |||
1322 | |||
1323 | |||
1324 | float taperX1; | ||
1325 | float taperY1; | ||
1326 | float taperX; | ||
1327 | float taperY; | ||
1328 | float pathBegin; | ||
1329 | float pathEnd; | ||
1330 | float profileBegin; | ||
1331 | float profileEnd; | ||
1332 | |||
1333 | if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible) | ||
1334 | { | ||
1335 | taperX1 = BaseShape.PathScaleX * 0.01f; | ||
1336 | if (taperX1 > 1.0f) | ||
1337 | taperX1 = 2.0f - taperX1; | ||
1338 | taperX = 1.0f - taperX1; | ||
1339 | |||
1340 | taperY1 = BaseShape.PathScaleY * 0.01f; | ||
1341 | if (taperY1 > 1.0f) | ||
1342 | taperY1 = 2.0f - taperY1; | ||
1343 | taperY = 1.0f - taperY1; | ||
1344 | } | ||
1345 | else | ||
1346 | { | ||
1347 | taperX = BaseShape.PathTaperX * 0.01f; | ||
1348 | if (taperX < 0.0f) | ||
1349 | taperX = -taperX; | ||
1350 | taperX1 = 1.0f - taperX; | ||
1351 | |||
1352 | taperY = BaseShape.PathTaperY * 0.01f; | ||
1353 | if (taperY < 0.0f) | ||
1354 | taperY = -taperY; | ||
1355 | taperY1 = 1.0f - taperY; | ||
1356 | |||
1357 | } | ||
1358 | |||
1359 | |||
1360 | volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); | ||
1361 | |||
1362 | pathBegin = (float)BaseShape.PathBegin * 2.0e-5f; | ||
1363 | pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f; | ||
1364 | volume *= (pathEnd - pathBegin); | ||
1365 | |||
1366 | // this is crude aproximation | ||
1367 | profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f; | ||
1368 | profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; | ||
1369 | volume *= (profileEnd - profileBegin); | ||
1370 | |||
1371 | returnMass = _density * volume; | ||
1372 | |||
1373 | /* Comment out code that computes the mass of the linkset. That is done in the Linkset class. | ||
1374 | if (IsRootOfLinkset) | ||
1375 | { | ||
1376 | foreach (BSPrim prim in _childrenPrims) | ||
1377 | { | ||
1378 | returnMass += prim.CalculateMass(); | ||
1379 | } | ||
1380 | } | ||
1381 | */ | ||
1382 | |||
1383 | returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); | ||
1384 | |||
1385 | return returnMass; | ||
1386 | }// end CalculateMass | ||
1387 | #endregion Mass Calculation | ||
1388 | |||
1389 | // Rebuild the geometry and object. | ||
1390 | // This is called when the shape changes so we need to recreate the mesh/hull. | ||
1391 | // Called at taint-time!!! | ||
1392 | public void CreateGeomAndObject(bool forceRebuild) | ||
1393 | { | ||
1394 | // If this prim is part of a linkset, we must remove and restore the physical | ||
1395 | // links if the body is rebuilt. | ||
1396 | bool needToRestoreLinkset = false; | ||
1397 | bool needToRestoreVehicle = false; | ||
1398 | |||
1399 | // Create the correct physical representation for this type of object. | ||
1400 | // Updates PhysBody and PhysShape with the new information. | ||
1401 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. | ||
1402 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) | ||
1403 | { | ||
1404 | // Called if the current prim body is about to be destroyed. | ||
1405 | // Remove all the physical dependencies on the old body. | ||
1406 | // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) | ||
1407 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); | ||
1408 | needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); | ||
1409 | }); | ||
1410 | |||
1411 | if (needToRestoreLinkset) | ||
1412 | { | ||
1413 | // If physical body dependencies were removed, restore them | ||
1414 | Linkset.RestoreBodyDependencies(this); | ||
1415 | } | ||
1416 | if (needToRestoreVehicle) | ||
1417 | { | ||
1418 | // If physical body dependencies were removed, restore them | ||
1419 | _vehicle.RestoreBodyDependencies(this); | ||
1420 | } | ||
1421 | |||
1422 | // Make sure the properties are set on the new object | ||
1423 | UpdatePhysicalParameters(); | ||
1424 | return; | ||
1425 | } | ||
1426 | |||
1427 | // The physics engine says that properties have updated. Update same and inform | ||
1428 | // the world that things have changed. | ||
1429 | // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate() | ||
1430 | enum UpdatedProperties { | ||
1431 | Position = 1 << 0, | ||
1432 | Rotation = 1 << 1, | ||
1433 | Velocity = 1 << 2, | ||
1434 | Acceleration = 1 << 3, | ||
1435 | RotationalVel = 1 << 4 | ||
1436 | } | ||
1437 | |||
1438 | const float ROTATION_TOLERANCE = 0.01f; | ||
1439 | const float VELOCITY_TOLERANCE = 0.001f; | ||
1440 | const float POSITION_TOLERANCE = 0.05f; | ||
1441 | const float ACCELERATION_TOLERANCE = 0.01f; | ||
1442 | const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; | ||
1443 | |||
1444 | public override void UpdateProperties(EntityProperties entprop) | ||
1445 | { | ||
1446 | // Updates only for individual prims and for the root object of a linkset. | ||
1447 | if (Linkset.IsRoot(this)) | ||
1448 | { | ||
1449 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet | ||
1450 | // TODO: handle physics introduced by Bullet with computed vehicle physics. | ||
1451 | if (_vehicle.IsActive) | ||
1452 | { | ||
1453 | entprop.RotationalVelocity = OMV.Vector3.Zero; | ||
1454 | } | ||
1455 | |||
1456 | // Assign directly to the local variables so the normal set action does not happen | ||
1457 | _position = entprop.Position; | ||
1458 | _orientation = entprop.Rotation; | ||
1459 | _velocity = entprop.Velocity; | ||
1460 | _acceleration = entprop.Acceleration; | ||
1461 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1462 | |||
1463 | // The sanity check can change the velocity and/or position. | ||
1464 | if (IsPhysical && PositionSanityCheck(true)) | ||
1465 | { | ||
1466 | entprop.Position = _position; | ||
1467 | entprop.Velocity = _velocity; | ||
1468 | } | ||
1469 | |||
1470 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG | ||
1471 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", | ||
1472 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); | ||
1473 | |||
1474 | // remember the current and last set values | ||
1475 | LastEntityProperties = CurrentEntityProperties; | ||
1476 | CurrentEntityProperties = entprop; | ||
1477 | |||
1478 | base.RequestPhysicsterseUpdate(); | ||
1479 | } | ||
1480 | /* | ||
1481 | else | ||
1482 | { | ||
1483 | // For debugging, report the movement of children | ||
1484 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
1485 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | ||
1486 | entprop.Acceleration, entprop.RotationalVelocity); | ||
1487 | } | ||
1488 | */ | ||
1489 | |||
1490 | // The linkset implimentation might want to know about this. | ||
1491 | Linkset.UpdateProperties(this, true); | ||
1492 | } | ||
1493 | } | ||
1494 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs new file mode 100644 index 0000000..1a7c34b --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs | |||
@@ -0,0 +1,957 @@ | |||
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.Runtime.InteropServices; | ||
30 | using System.Text; | ||
31 | using System.Threading; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Framework; | ||
34 | using OpenSim.Region.CoreModules; | ||
35 | using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging; | ||
36 | using OpenSim.Region.Physics.Manager; | ||
37 | using Nini.Config; | ||
38 | using log4net; | ||
39 | using OpenMetaverse; | ||
40 | |||
41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) | ||
42 | // Based on material, set density and friction | ||
43 | // More efficient memory usage when passing hull information from BSPrim to BulletSim | ||
44 | // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect | ||
45 | // Implement LockAngularMotion | ||
46 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? | ||
47 | // Check terrain size. 128 or 127? | ||
48 | // Raycast | ||
49 | // | ||
50 | namespace OpenSim.Region.Physics.BulletSNPlugin | ||
51 | { | ||
52 | public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||
53 | { | ||
54 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
55 | private static readonly string LogHeader = "[BULLETS SCENE]"; | ||
56 | |||
57 | // The name of the region we're working for. | ||
58 | public string RegionName { get; private set; } | ||
59 | |||
60 | public string BulletSimVersion = "?"; | ||
61 | |||
62 | public Dictionary<uint, BSPhysObject> PhysObjects; | ||
63 | public BSShapeCollection Shapes; | ||
64 | |||
65 | // Keeping track of the objects with collisions so we can report begin and end of a collision | ||
66 | public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>(); | ||
67 | public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>(); | ||
68 | // Keep track of all the avatars so we can send them a collision event | ||
69 | // every tick so OpenSim will update its animation. | ||
70 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); | ||
71 | |||
72 | // let my minuions use my logger | ||
73 | public ILog Logger { get { return m_log; } } | ||
74 | |||
75 | public IMesher mesher; | ||
76 | public uint WorldID { get; private set; } | ||
77 | public BulletWorld World { get; private set; } | ||
78 | |||
79 | // All the constraints that have been allocated in this instance. | ||
80 | public BSConstraintCollection Constraints { get; private set; } | ||
81 | |||
82 | // Simulation parameters | ||
83 | internal int m_maxSubSteps; | ||
84 | internal float m_fixedTimeStep; | ||
85 | internal long m_simulationStep = 0; | ||
86 | public long SimulationStep { get { return m_simulationStep; } } | ||
87 | internal int m_taintsToProcessPerStep; | ||
88 | internal float LastTimeStep { get; private set; } | ||
89 | |||
90 | // Physical objects can register for prestep or poststep events | ||
91 | public delegate void PreStepAction(float timeStep); | ||
92 | public delegate void PostStepAction(float timeStep); | ||
93 | public event PreStepAction BeforeStep; | ||
94 | public event PreStepAction AfterStep; | ||
95 | |||
96 | // A value of the time now so all the collision and update routines do not have to get their own | ||
97 | // Set to 'now' just before all the prims and actors are called for collisions and updates | ||
98 | public int SimulationNowTime { get; private set; } | ||
99 | |||
100 | // True if initialized and ready to do simulation steps | ||
101 | private bool m_initialized = false; | ||
102 | |||
103 | // Flag which is true when processing taints. | ||
104 | // Not guaranteed to be correct all the time (don't depend on this) but good for debugging. | ||
105 | public bool InTaintTime { get; private set; } | ||
106 | |||
107 | // Pinned memory used to pass step information between managed and unmanaged | ||
108 | internal int m_maxCollisionsPerFrame; | ||
109 | private List<BulletXNA.CollisionDesc> m_collisionArray; | ||
110 | //private GCHandle m_collisionArrayPinnedHandle; | ||
111 | |||
112 | internal int m_maxUpdatesPerFrame; | ||
113 | private List<BulletXNA.EntityProperties> m_updateArray; | ||
114 | //private GCHandle m_updateArrayPinnedHandle; | ||
115 | |||
116 | |||
117 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero | ||
118 | public const uint GROUNDPLANE_ID = 1; | ||
119 | public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here | ||
120 | |||
121 | public float SimpleWaterLevel { get; set; } | ||
122 | public BSTerrainManager TerrainManager { get; private set; } | ||
123 | |||
124 | public ConfigurationParameters Params | ||
125 | { | ||
126 | get { return UnmanagedParams[0]; } | ||
127 | } | ||
128 | public Vector3 DefaultGravity | ||
129 | { | ||
130 | get { return new Vector3(0f, 0f, Params.gravity); } | ||
131 | } | ||
132 | // Just the Z value of the gravity | ||
133 | public float DefaultGravityZ | ||
134 | { | ||
135 | get { return Params.gravity; } | ||
136 | } | ||
137 | |||
138 | // When functions in the unmanaged code must be called, it is only | ||
139 | // done at a known time just before the simulation step. The taint | ||
140 | // system saves all these function calls and executes them in | ||
141 | // order before the simulation. | ||
142 | public delegate void TaintCallback(); | ||
143 | private struct TaintCallbackEntry | ||
144 | { | ||
145 | public String ident; | ||
146 | public TaintCallback callback; | ||
147 | public TaintCallbackEntry(string i, TaintCallback c) | ||
148 | { | ||
149 | ident = i; | ||
150 | callback = c; | ||
151 | } | ||
152 | } | ||
153 | private Object _taintLock = new Object(); // lock for using the next object | ||
154 | private List<TaintCallbackEntry> _taintOperations; | ||
155 | private Dictionary<string, TaintCallbackEntry> _postTaintOperations; | ||
156 | private List<TaintCallbackEntry> _postStepOperations; | ||
157 | |||
158 | // A pointer to an instance if this structure is passed to the C++ code | ||
159 | // Used to pass basic configuration values to the unmanaged code. | ||
160 | internal ConfigurationParameters[] UnmanagedParams; | ||
161 | //GCHandle m_paramsHandle; | ||
162 | |||
163 | // Handle to the callback used by the unmanaged code to call into the managed code. | ||
164 | // Used for debug logging. | ||
165 | // Need to store the handle in a persistant variable so it won't be freed. | ||
166 | private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; | ||
167 | |||
168 | // Sometimes you just have to log everything. | ||
169 | public Logging.LogWriter PhysicsLogging; | ||
170 | private bool m_physicsLoggingEnabled; | ||
171 | private string m_physicsLoggingDir; | ||
172 | private string m_physicsLoggingPrefix; | ||
173 | private int m_physicsLoggingFileMinutes; | ||
174 | private bool m_physicsLoggingDoFlush; | ||
175 | // 'true' of the vehicle code is to log lots of details | ||
176 | public bool VehicleLoggingEnabled { get; private set; } | ||
177 | public bool VehiclePhysicalLoggingEnabled { get; private set; } | ||
178 | |||
179 | #region Construction and Initialization | ||
180 | public BSScene(string identifier) | ||
181 | { | ||
182 | m_initialized = false; | ||
183 | // we are passed the name of the region we're working for. | ||
184 | RegionName = identifier; | ||
185 | } | ||
186 | |||
187 | public override void Initialise(IMesher meshmerizer, IConfigSource config) | ||
188 | { | ||
189 | mesher = meshmerizer; | ||
190 | _taintOperations = new List<TaintCallbackEntry>(); | ||
191 | _postTaintOperations = new Dictionary<string, TaintCallbackEntry>(); | ||
192 | _postStepOperations = new List<TaintCallbackEntry>(); | ||
193 | PhysObjects = new Dictionary<uint, BSPhysObject>(); | ||
194 | Shapes = new BSShapeCollection(this); | ||
195 | |||
196 | // Allocate pinned memory to pass parameters. | ||
197 | UnmanagedParams = new ConfigurationParameters[1]; | ||
198 | //m_paramsHandle = GCHandle.Alloc(UnmanagedParams, GCHandleType.Pinned); | ||
199 | |||
200 | // Set default values for physics parameters plus any overrides from the ini file | ||
201 | GetInitialParameterValues(config); | ||
202 | |||
203 | // allocate more pinned memory close to the above in an attempt to get the memory all together | ||
204 | m_collisionArray = new List<BulletXNA.CollisionDesc>(); | ||
205 | //m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned); | ||
206 | m_updateArray = new List<BulletXNA.EntityProperties>(); | ||
207 | //m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); | ||
208 | |||
209 | // Enable very detailed logging. | ||
210 | // By creating an empty logger when not logging, the log message invocation code | ||
211 | // can be left in and every call doesn't have to check for null. | ||
212 | if (m_physicsLoggingEnabled) | ||
213 | { | ||
214 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); | ||
215 | PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages. | ||
216 | } | ||
217 | else | ||
218 | { | ||
219 | PhysicsLogging = new Logging.LogWriter(); | ||
220 | } | ||
221 | |||
222 | // If Debug logging level, enable logging from the unmanaged code | ||
223 | m_DebugLogCallbackHandle = null; | ||
224 | if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) | ||
225 | { | ||
226 | m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); | ||
227 | if (PhysicsLogging.Enabled) | ||
228 | // The handle is saved in a variable to make sure it doesn't get freed after this call | ||
229 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); | ||
230 | else | ||
231 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); | ||
232 | } | ||
233 | |||
234 | // Get the version of the DLL | ||
235 | // TODO: this doesn't work yet. Something wrong with marshaling the returned string. | ||
236 | // BulletSimVersion = BulletSimAPI.GetVersion(); | ||
237 | // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); | ||
238 | |||
239 | // The bounding box for the simulated world. The origin is 0,0,0 unless we're | ||
240 | // a child in a mega-region. | ||
241 | // Bullet actually doesn't care about the extents of the simulated | ||
242 | // area. It tracks active objects no matter where they are. | ||
243 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | ||
244 | |||
245 | // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); | ||
246 | |||
247 | World = new BulletWorld(0, this, BulletSimAPI.Initialize2(worldExtent, UnmanagedParams, | ||
248 | m_maxCollisionsPerFrame, ref m_collisionArray, | ||
249 | m_maxUpdatesPerFrame,ref m_updateArray, | ||
250 | m_DebugLogCallbackHandle)); | ||
251 | |||
252 | Constraints = new BSConstraintCollection(World); | ||
253 | |||
254 | TerrainManager = new BSTerrainManager(this); | ||
255 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); | ||
256 | |||
257 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); | ||
258 | |||
259 | InTaintTime = false; | ||
260 | m_initialized = true; | ||
261 | } | ||
262 | |||
263 | // All default parameter values are set here. There should be no values set in the | ||
264 | // variable definitions. | ||
265 | private void GetInitialParameterValues(IConfigSource config) | ||
266 | { | ||
267 | ConfigurationParameters parms = new ConfigurationParameters(); | ||
268 | UnmanagedParams[0] = parms; | ||
269 | |||
270 | BSParam.SetParameterDefaultValues(this); | ||
271 | |||
272 | if (config != null) | ||
273 | { | ||
274 | // If there are specifications in the ini file, use those values | ||
275 | IConfig pConfig = config.Configs["BulletSim"]; | ||
276 | if (pConfig != null) | ||
277 | { | ||
278 | BSParam.SetParameterConfigurationValues(this, pConfig); | ||
279 | |||
280 | // Very detailed logging for physics debugging | ||
281 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); | ||
282 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); | ||
283 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); | ||
284 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); | ||
285 | m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false); | ||
286 | // Very detailed logging for vehicle debugging | ||
287 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); | ||
288 | VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false); | ||
289 | |||
290 | // Do any replacements in the parameters | ||
291 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); | ||
292 | } | ||
293 | |||
294 | // The material characteristics. | ||
295 | BSMaterials.InitializeFromDefaults(Params); | ||
296 | if (pConfig != null) | ||
297 | { | ||
298 | // Let the user add new and interesting material property values. | ||
299 | BSMaterials.InitializefromParameters(pConfig); | ||
300 | } | ||
301 | } | ||
302 | } | ||
303 | |||
304 | // A helper function that handles a true/false parameter and returns the proper float number encoding | ||
305 | float ParamBoolean(IConfig config, string parmName, float deflt) | ||
306 | { | ||
307 | float ret = deflt; | ||
308 | if (config.Contains(parmName)) | ||
309 | { | ||
310 | ret = ConfigurationParameters.numericFalse; | ||
311 | if (config.GetBoolean(parmName, false)) | ||
312 | { | ||
313 | ret = ConfigurationParameters.numericTrue; | ||
314 | } | ||
315 | } | ||
316 | return ret; | ||
317 | } | ||
318 | |||
319 | // Called directly from unmanaged code so don't do much | ||
320 | private void BulletLogger(string msg) | ||
321 | { | ||
322 | m_log.Debug("[BULLETS UNMANAGED]:" + msg); | ||
323 | } | ||
324 | |||
325 | // Called directly from unmanaged code so don't do much | ||
326 | private void BulletLoggerPhysLog(string msg) | ||
327 | { | ||
328 | DetailLog("[BULLETS UNMANAGED]:" + msg); | ||
329 | } | ||
330 | |||
331 | public override void Dispose() | ||
332 | { | ||
333 | // m_log.DebugFormat("{0}: Dispose()", LogHeader); | ||
334 | |||
335 | // make sure no stepping happens while we're deleting stuff | ||
336 | m_initialized = false; | ||
337 | |||
338 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) | ||
339 | { | ||
340 | kvp.Value.Destroy(); | ||
341 | } | ||
342 | PhysObjects.Clear(); | ||
343 | |||
344 | // Now that the prims are all cleaned up, there should be no constraints left | ||
345 | if (Constraints != null) | ||
346 | { | ||
347 | Constraints.Dispose(); | ||
348 | Constraints = null; | ||
349 | } | ||
350 | |||
351 | if (Shapes != null) | ||
352 | { | ||
353 | Shapes.Dispose(); | ||
354 | Shapes = null; | ||
355 | } | ||
356 | |||
357 | if (TerrainManager != null) | ||
358 | { | ||
359 | TerrainManager.ReleaseGroundPlaneAndTerrain(); | ||
360 | TerrainManager.Dispose(); | ||
361 | TerrainManager = null; | ||
362 | } | ||
363 | |||
364 | // Anything left in the unmanaged code should be cleaned out | ||
365 | BulletSimAPI.Shutdown2(World.ptr); | ||
366 | |||
367 | // Not logging any more | ||
368 | PhysicsLogging.Close(); | ||
369 | } | ||
370 | #endregion // Construction and Initialization | ||
371 | |||
372 | #region Prim and Avatar addition and removal | ||
373 | |||
374 | public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) | ||
375 | { | ||
376 | m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader); | ||
377 | return null; | ||
378 | } | ||
379 | |||
380 | public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying) | ||
381 | { | ||
382 | // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName); | ||
383 | |||
384 | if (!m_initialized) return null; | ||
385 | |||
386 | BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); | ||
387 | lock (PhysObjects) PhysObjects.Add(localID, actor); | ||
388 | |||
389 | // TODO: Remove kludge someday. | ||
390 | // We must generate a collision for avatars whether they collide or not. | ||
391 | // This is required by OpenSim to update avatar animations, etc. | ||
392 | lock (m_avatars) m_avatars.Add(actor); | ||
393 | |||
394 | return actor; | ||
395 | } | ||
396 | |||
397 | public override void RemoveAvatar(PhysicsActor actor) | ||
398 | { | ||
399 | // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader); | ||
400 | |||
401 | if (!m_initialized) return; | ||
402 | |||
403 | BSCharacter bsactor = actor as BSCharacter; | ||
404 | if (bsactor != null) | ||
405 | { | ||
406 | try | ||
407 | { | ||
408 | lock (PhysObjects) PhysObjects.Remove(actor.LocalID); | ||
409 | // Remove kludge someday | ||
410 | lock (m_avatars) m_avatars.Remove(bsactor); | ||
411 | } | ||
412 | catch (Exception e) | ||
413 | { | ||
414 | m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e); | ||
415 | } | ||
416 | bsactor.Destroy(); | ||
417 | // bsactor.dispose(); | ||
418 | } | ||
419 | } | ||
420 | |||
421 | public override void RemovePrim(PhysicsActor prim) | ||
422 | { | ||
423 | if (!m_initialized) return; | ||
424 | |||
425 | BSPrim bsprim = prim as BSPrim; | ||
426 | if (bsprim != null) | ||
427 | { | ||
428 | DetailLog("{0},RemovePrim,call", bsprim.LocalID); | ||
429 | // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); | ||
430 | try | ||
431 | { | ||
432 | lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID); | ||
433 | } | ||
434 | catch (Exception e) | ||
435 | { | ||
436 | m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e); | ||
437 | } | ||
438 | bsprim.Destroy(); | ||
439 | // bsprim.dispose(); | ||
440 | } | ||
441 | else | ||
442 | { | ||
443 | m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader); | ||
444 | } | ||
445 | } | ||
446 | |||
447 | public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, | ||
448 | Vector3 size, Quaternion rotation, bool isPhysical, uint localID) | ||
449 | { | ||
450 | // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName); | ||
451 | |||
452 | if (!m_initialized) return null; | ||
453 | |||
454 | DetailLog("{0},AddPrimShape,call", localID); | ||
455 | |||
456 | BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); | ||
457 | lock (PhysObjects) PhysObjects.Add(localID, prim); | ||
458 | return prim; | ||
459 | } | ||
460 | |||
461 | // This is a call from the simulator saying that some physical property has been updated. | ||
462 | // The BulletSim driver senses the changing of relevant properties so this taint | ||
463 | // information call is not needed. | ||
464 | public override void AddPhysicsActorTaint(PhysicsActor prim) { } | ||
465 | |||
466 | #endregion // Prim and Avatar addition and removal | ||
467 | |||
468 | #region Simulation | ||
469 | // Simulate one timestep | ||
470 | public override float Simulate(float timeStep) | ||
471 | { | ||
472 | // prevent simulation until we've been initialized | ||
473 | if (!m_initialized) return 5.0f; | ||
474 | |||
475 | LastTimeStep = timeStep; | ||
476 | |||
477 | int updatedEntityCount = 0; | ||
478 | //Object updatedEntitiesPtr; | ||
479 | int collidersCount = 0; | ||
480 | //Object collidersPtr; | ||
481 | |||
482 | int beforeTime = 0; | ||
483 | int simTime = 0; | ||
484 | |||
485 | // update the prim states while we know the physics engine is not busy | ||
486 | int numTaints = _taintOperations.Count; | ||
487 | |||
488 | InTaintTime = true; // Only used for debugging so locking is not necessary. | ||
489 | |||
490 | ProcessTaints(); | ||
491 | |||
492 | // Some of the physical objects requre individual, pre-step calls | ||
493 | TriggerPreStepEvent(timeStep); | ||
494 | |||
495 | // the prestep actions might have added taints | ||
496 | ProcessTaints(); | ||
497 | |||
498 | InTaintTime = false; // Only used for debugging so locking is not necessary. | ||
499 | |||
500 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. | ||
501 | // Only enable this in a limited test world with few objects. | ||
502 | // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG | ||
503 | |||
504 | // step the physical world one interval | ||
505 | m_simulationStep++; | ||
506 | int numSubSteps = 0; | ||
507 | |||
508 | try | ||
509 | { | ||
510 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | ||
511 | |||
512 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, | ||
513 | out updatedEntityCount, out m_updateArray, out collidersCount, out m_collisionArray); | ||
514 | |||
515 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); | ||
516 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", | ||
517 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | ||
518 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | ||
519 | } | ||
520 | catch (Exception e) | ||
521 | { | ||
522 | m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}", | ||
523 | LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e); | ||
524 | DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}", | ||
525 | DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount); | ||
526 | updatedEntityCount = 0; | ||
527 | collidersCount = 0; | ||
528 | } | ||
529 | |||
530 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in. | ||
531 | |||
532 | // Get a value for 'now' so all the collision and update routines don't have to get their own. | ||
533 | SimulationNowTime = Util.EnvironmentTickCount(); | ||
534 | |||
535 | // If there were collisions, process them by sending the event to the prim. | ||
536 | // Collisions must be processed before updates. | ||
537 | if (collidersCount > 0) | ||
538 | { | ||
539 | for (int ii = 0; ii < collidersCount; ii++) | ||
540 | { | ||
541 | uint cA = m_collisionArray[ii].aID; | ||
542 | uint cB = m_collisionArray[ii].bID; | ||
543 | Vector3 point = new Vector3(m_collisionArray[ii].point.X, m_collisionArray[ii].point.Y, | ||
544 | m_collisionArray[ii].point.Z); | ||
545 | Vector3 normal = new Vector3(m_collisionArray[ii].normal.X, m_collisionArray[ii].normal.Y, | ||
546 | m_collisionArray[ii].normal.Z); | ||
547 | SendCollision(cA, cB, point, normal, 0.01f); | ||
548 | SendCollision(cB, cA, point, -normal, 0.01f); | ||
549 | } | ||
550 | } | ||
551 | |||
552 | // The above SendCollision's batch up the collisions on the objects. | ||
553 | // Now push the collisions into the simulator. | ||
554 | if (ObjectsWithCollisions.Count > 0) | ||
555 | { | ||
556 | foreach (BSPhysObject bsp in ObjectsWithCollisions) | ||
557 | if (!bsp.SendCollisions()) | ||
558 | { | ||
559 | // If the object is done colliding, see that it's removed from the colliding list | ||
560 | ObjectsWithNoMoreCollisions.Add(bsp); | ||
561 | } | ||
562 | } | ||
563 | |||
564 | // This is a kludge to get avatar movement updates. | ||
565 | // The simulator expects collisions for avatars even if there are have been no collisions. | ||
566 | // The event updates avatar animations and stuff. | ||
567 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
568 | foreach (BSPhysObject bsp in m_avatars) | ||
569 | if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice | ||
570 | bsp.SendCollisions(); | ||
571 | |||
572 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | ||
573 | // Not done above because it is inside an iteration of ObjectWithCollisions. | ||
574 | // This complex collision processing is required to create an empty collision | ||
575 | // event call after all collisions have happened on an object. This enables | ||
576 | // the simulator to generate the 'collision end' event. | ||
577 | if (ObjectsWithNoMoreCollisions.Count > 0) | ||
578 | { | ||
579 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | ||
580 | ObjectsWithCollisions.Remove(po); | ||
581 | ObjectsWithNoMoreCollisions.Clear(); | ||
582 | } | ||
583 | // Done with collisions. | ||
584 | |||
585 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine | ||
586 | if (updatedEntityCount > 0) | ||
587 | { | ||
588 | for (int ii = 0; ii < updatedEntityCount; ii++) | ||
589 | { | ||
590 | |||
591 | BulletXNA.EntityProperties entprop = m_updateArray[ii]; | ||
592 | BSPhysObject pobj; | ||
593 | if (PhysObjects.TryGetValue(entprop.ID, out pobj)) | ||
594 | { | ||
595 | EntityProperties prop = new EntityProperties() | ||
596 | { | ||
597 | Acceleration = new Vector3(entprop.Acceleration.X, entprop.Acceleration.Y, entprop.Acceleration.Z), | ||
598 | ID = entprop.ID, | ||
599 | Position = new Vector3(entprop.Position.X,entprop.Position.Y,entprop.Position.Z), | ||
600 | Rotation = new Quaternion(entprop.Rotation.X,entprop.Rotation.Y,entprop.Rotation.Z,entprop.Rotation.W), | ||
601 | RotationalVelocity = new Vector3(entprop.AngularVelocity.X,entprop.AngularVelocity.Y,entprop.AngularVelocity.Z), | ||
602 | Velocity = new Vector3(entprop.Velocity.X,entprop.Velocity.Y,entprop.Velocity.Z) | ||
603 | }; | ||
604 | //m_log.Debug(pobj.Name + ":" + prop.ToString() + "\n"); | ||
605 | pobj.UpdateProperties(prop); | ||
606 | } | ||
607 | } | ||
608 | } | ||
609 | |||
610 | TriggerPostStepEvent(timeStep); | ||
611 | |||
612 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. | ||
613 | // Only enable this in a limited test world with few objects. | ||
614 | // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG | ||
615 | |||
616 | // The physics engine returns the number of milliseconds it simulated this call. | ||
617 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | ||
618 | // Multiply by 55 to give a nominal frame rate of 55. | ||
619 | return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f; | ||
620 | } | ||
621 | |||
622 | // Something has collided | ||
623 | private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration) | ||
624 | { | ||
625 | if (localID <= TerrainManager.HighestTerrainID) | ||
626 | { | ||
627 | return; // don't send collisions to the terrain | ||
628 | } | ||
629 | |||
630 | BSPhysObject collider; | ||
631 | if (!PhysObjects.TryGetValue(localID, out collider)) | ||
632 | { | ||
633 | // If the object that is colliding cannot be found, just ignore the collision. | ||
634 | DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith); | ||
635 | return; | ||
636 | } | ||
637 | |||
638 | // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. | ||
639 | BSPhysObject collidee = null; | ||
640 | PhysObjects.TryGetValue(collidingWith, out collidee); | ||
641 | |||
642 | // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); | ||
643 | |||
644 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) | ||
645 | { | ||
646 | // If a collision was posted, remember to send it to the simulator | ||
647 | ObjectsWithCollisions.Add(collider); | ||
648 | } | ||
649 | |||
650 | return; | ||
651 | } | ||
652 | |||
653 | #endregion // Simulation | ||
654 | |||
655 | public override void GetResults() { } | ||
656 | |||
657 | #region Terrain | ||
658 | |||
659 | public override void SetTerrain(float[] heightMap) { | ||
660 | TerrainManager.SetTerrain(heightMap); | ||
661 | } | ||
662 | |||
663 | public override void SetWaterLevel(float baseheight) | ||
664 | { | ||
665 | SimpleWaterLevel = baseheight; | ||
666 | } | ||
667 | |||
668 | public override void DeleteTerrain() | ||
669 | { | ||
670 | // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); | ||
671 | } | ||
672 | |||
673 | // Although no one seems to check this, I do support combining. | ||
674 | public override bool SupportsCombining() | ||
675 | { | ||
676 | return TerrainManager.SupportsCombining(); | ||
677 | } | ||
678 | // This call says I am a child to region zero in a mega-region. 'pScene' is that | ||
679 | // of region zero, 'offset' is my offset from regions zero's origin, and | ||
680 | // 'extents' is the largest XY that is handled in my region. | ||
681 | public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) | ||
682 | { | ||
683 | TerrainManager.Combine(pScene, offset, extents); | ||
684 | } | ||
685 | |||
686 | // Unhook all the combining that I know about. | ||
687 | public override void UnCombine(PhysicsScene pScene) | ||
688 | { | ||
689 | TerrainManager.UnCombine(pScene); | ||
690 | } | ||
691 | |||
692 | #endregion // Terrain | ||
693 | |||
694 | public override Dictionary<uint, float> GetTopColliders() | ||
695 | { | ||
696 | return new Dictionary<uint, float>(); | ||
697 | } | ||
698 | |||
699 | public override bool IsThreaded { get { return false; } } | ||
700 | |||
701 | #region Taints | ||
702 | // The simulation execution order is: | ||
703 | // Simulate() | ||
704 | // DoOneTimeTaints | ||
705 | // TriggerPreStepEvent | ||
706 | // DoOneTimeTaints | ||
707 | // Step() | ||
708 | // ProcessAndForwardCollisions | ||
709 | // ProcessAndForwardPropertyUpdates | ||
710 | // TriggerPostStepEvent | ||
711 | |||
712 | // Calls to the PhysicsActors can't directly call into the physics engine | ||
713 | // because it might be busy. We delay changes to a known time. | ||
714 | // We rely on C#'s closure to save and restore the context for the delegate. | ||
715 | public void TaintedObject(String ident, TaintCallback callback) | ||
716 | { | ||
717 | if (!m_initialized) return; | ||
718 | |||
719 | lock (_taintLock) | ||
720 | { | ||
721 | _taintOperations.Add(new TaintCallbackEntry(ident, callback)); | ||
722 | } | ||
723 | |||
724 | return; | ||
725 | } | ||
726 | |||
727 | // Sometimes a potentially tainted operation can be used in and out of taint time. | ||
728 | // This routine executes the command immediately if in taint-time otherwise it is queued. | ||
729 | public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback) | ||
730 | { | ||
731 | if (inTaintTime) | ||
732 | callback(); | ||
733 | else | ||
734 | TaintedObject(ident, callback); | ||
735 | } | ||
736 | |||
737 | private void TriggerPreStepEvent(float timeStep) | ||
738 | { | ||
739 | PreStepAction actions = BeforeStep; | ||
740 | if (actions != null) | ||
741 | actions(timeStep); | ||
742 | |||
743 | } | ||
744 | |||
745 | private void TriggerPostStepEvent(float timeStep) | ||
746 | { | ||
747 | PreStepAction actions = AfterStep; | ||
748 | if (actions != null) | ||
749 | actions(timeStep); | ||
750 | |||
751 | } | ||
752 | |||
753 | // When someone tries to change a property on a BSPrim or BSCharacter, the object queues | ||
754 | // a callback into itself to do the actual property change. That callback is called | ||
755 | // here just before the physics engine is called to step the simulation. | ||
756 | public void ProcessTaints() | ||
757 | { | ||
758 | ProcessRegularTaints(); | ||
759 | ProcessPostTaintTaints(); | ||
760 | } | ||
761 | |||
762 | private void ProcessRegularTaints() | ||
763 | { | ||
764 | if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process | ||
765 | { | ||
766 | // swizzle a new list into the list location so we can process what's there | ||
767 | List<TaintCallbackEntry> oldList; | ||
768 | lock (_taintLock) | ||
769 | { | ||
770 | oldList = _taintOperations; | ||
771 | _taintOperations = new List<TaintCallbackEntry>(); | ||
772 | } | ||
773 | |||
774 | foreach (TaintCallbackEntry tcbe in oldList) | ||
775 | { | ||
776 | try | ||
777 | { | ||
778 | DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG | ||
779 | tcbe.callback(); | ||
780 | } | ||
781 | catch (Exception e) | ||
782 | { | ||
783 | m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); | ||
784 | } | ||
785 | } | ||
786 | oldList.Clear(); | ||
787 | } | ||
788 | } | ||
789 | |||
790 | // Schedule an update to happen after all the regular taints are processed. | ||
791 | // Note that new requests for the same operation ("ident") for the same object ("ID") | ||
792 | // will replace any previous operation by the same object. | ||
793 | public void PostTaintObject(String ident, uint ID, TaintCallback callback) | ||
794 | { | ||
795 | string uniqueIdent = ident + "-" + ID.ToString(); | ||
796 | lock (_taintLock) | ||
797 | { | ||
798 | _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback); | ||
799 | } | ||
800 | |||
801 | return; | ||
802 | } | ||
803 | |||
804 | // Taints that happen after the normal taint processing but before the simulation step. | ||
805 | private void ProcessPostTaintTaints() | ||
806 | { | ||
807 | if (_postTaintOperations.Count > 0) | ||
808 | { | ||
809 | Dictionary<string, TaintCallbackEntry> oldList; | ||
810 | lock (_taintLock) | ||
811 | { | ||
812 | oldList = _postTaintOperations; | ||
813 | _postTaintOperations = new Dictionary<string, TaintCallbackEntry>(); | ||
814 | } | ||
815 | |||
816 | foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList) | ||
817 | { | ||
818 | try | ||
819 | { | ||
820 | DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG | ||
821 | kvp.Value.callback(); | ||
822 | } | ||
823 | catch (Exception e) | ||
824 | { | ||
825 | m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e); | ||
826 | } | ||
827 | } | ||
828 | oldList.Clear(); | ||
829 | } | ||
830 | } | ||
831 | |||
832 | // Only used for debugging. Does not change state of anything so locking is not necessary. | ||
833 | public bool AssertInTaintTime(string whereFrom) | ||
834 | { | ||
835 | if (!InTaintTime) | ||
836 | { | ||
837 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); | ||
838 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); | ||
839 | Util.PrintCallStack(DetailLog); | ||
840 | } | ||
841 | return InTaintTime; | ||
842 | } | ||
843 | |||
844 | #endregion // Taints | ||
845 | |||
846 | #region INI and command line parameter processing | ||
847 | |||
848 | #region IPhysicsParameters | ||
849 | // Get the list of parameters this physics engine supports | ||
850 | public PhysParameterEntry[] GetParameterList() | ||
851 | { | ||
852 | BSParam.BuildParameterTable(); | ||
853 | return BSParam.SettableParameters; | ||
854 | } | ||
855 | |||
856 | // Set parameter on a specific or all instances. | ||
857 | // Return 'false' if not able to set the parameter. | ||
858 | // Setting the value in the m_params block will change the value the physics engine | ||
859 | // will use the next time since it's pinned and shared memory. | ||
860 | // Some of the values require calling into the physics engine to get the new | ||
861 | // value activated ('terrainFriction' for instance). | ||
862 | public bool SetPhysicsParameter(string parm, float val, uint localID) | ||
863 | { | ||
864 | bool ret = false; | ||
865 | BSParam.ParameterDefn theParam; | ||
866 | if (BSParam.TryGetParameter(parm, out theParam)) | ||
867 | { | ||
868 | theParam.setter(this, parm, localID, val); | ||
869 | ret = true; | ||
870 | } | ||
871 | return ret; | ||
872 | } | ||
873 | |||
874 | // update all the localIDs specified | ||
875 | // If the local ID is APPLY_TO_NONE, just change the default value | ||
876 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs | ||
877 | // If the localID is a specific object, apply the parameter change to only that object | ||
878 | internal delegate void AssignVal(float x); | ||
879 | internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val) | ||
880 | { | ||
881 | List<uint> objectIDs = new List<uint>(); | ||
882 | switch (localID) | ||
883 | { | ||
884 | case PhysParameterEntry.APPLY_TO_NONE: | ||
885 | setDefault(val); // setting only the default value | ||
886 | // This will cause a call into the physical world if some operation is specified (SetOnObject). | ||
887 | objectIDs.Add(TERRAIN_ID); | ||
888 | TaintedUpdateParameter(parm, objectIDs, val); | ||
889 | break; | ||
890 | case PhysParameterEntry.APPLY_TO_ALL: | ||
891 | setDefault(val); // setting ALL also sets the default value | ||
892 | lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); | ||
893 | TaintedUpdateParameter(parm, objectIDs, val); | ||
894 | break; | ||
895 | default: | ||
896 | // setting only one localID | ||
897 | objectIDs.Add(localID); | ||
898 | TaintedUpdateParameter(parm, objectIDs, val); | ||
899 | break; | ||
900 | } | ||
901 | } | ||
902 | |||
903 | // schedule the actual updating of the paramter to when the phys engine is not busy | ||
904 | private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val) | ||
905 | { | ||
906 | float xval = val; | ||
907 | List<uint> xlIDs = lIDs; | ||
908 | string xparm = parm; | ||
909 | TaintedObject("BSScene.UpdateParameterSet", delegate() { | ||
910 | BSParam.ParameterDefn thisParam; | ||
911 | if (BSParam.TryGetParameter(xparm, out thisParam)) | ||
912 | { | ||
913 | if (thisParam.onObject != null) | ||
914 | { | ||
915 | foreach (uint lID in xlIDs) | ||
916 | { | ||
917 | BSPhysObject theObject = null; | ||
918 | PhysObjects.TryGetValue(lID, out theObject); | ||
919 | thisParam.onObject(this, theObject, xval); | ||
920 | } | ||
921 | } | ||
922 | } | ||
923 | }); | ||
924 | } | ||
925 | |||
926 | // Get parameter. | ||
927 | // Return 'false' if not able to get the parameter. | ||
928 | public bool GetPhysicsParameter(string parm, out float value) | ||
929 | { | ||
930 | float val = 0f; | ||
931 | bool ret = false; | ||
932 | BSParam.ParameterDefn theParam; | ||
933 | if (BSParam.TryGetParameter(parm, out theParam)) | ||
934 | { | ||
935 | val = theParam.getter(this); | ||
936 | ret = true; | ||
937 | } | ||
938 | value = val; | ||
939 | return ret; | ||
940 | } | ||
941 | |||
942 | #endregion IPhysicsParameters | ||
943 | |||
944 | #endregion Runtime settable parameters | ||
945 | |||
946 | // Invoke the detailed logger and output something if it's enabled. | ||
947 | public void DetailLog(string msg, params Object[] args) | ||
948 | { | ||
949 | PhysicsLogging.Write(msg, args); | ||
950 | // Add the Flush() if debugging crashes. Gets all the messages written out. | ||
951 | if (m_physicsLoggingDoFlush) PhysicsLogging.Flush(); | ||
952 | } | ||
953 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. | ||
954 | public const string DetailLogZero = "0000000000"; | ||
955 | |||
956 | } | ||
957 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs new file mode 100644 index 0000000..764aece --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs | |||
@@ -0,0 +1,1015 @@ | |||
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.BulletSNPlugin | ||
36 | { | ||
37 | public sealed class BSShapeCollection : IDisposable | ||
38 | { | ||
39 | private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; | ||
40 | |||
41 | private BSScene PhysicsScene { get; set; } | ||
42 | |||
43 | private Object m_collectionActivityLock = new Object(); | ||
44 | |||
45 | // Description of a Mesh | ||
46 | private struct MeshDesc | ||
47 | { | ||
48 | public Object ptr; | ||
49 | public int referenceCount; | ||
50 | public DateTime lastReferenced; | ||
51 | public UInt64 shapeKey; | ||
52 | } | ||
53 | |||
54 | // Description of a hull. | ||
55 | // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. | ||
56 | private struct HullDesc | ||
57 | { | ||
58 | public Object ptr; | ||
59 | public int referenceCount; | ||
60 | public DateTime lastReferenced; | ||
61 | public UInt64 shapeKey; | ||
62 | } | ||
63 | |||
64 | // The sharable set of meshes and hulls. Indexed by their shape hash. | ||
65 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); | ||
66 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); | ||
67 | |||
68 | private bool DDetail = false; | ||
69 | |||
70 | public BSShapeCollection(BSScene physScene) | ||
71 | { | ||
72 | PhysicsScene = physScene; | ||
73 | // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) | ||
74 | // While detailed debugging is still active, this is better than commenting out all the | ||
75 | // DetailLog statements. When debugging slows down, this and the protected logging | ||
76 | // statements can be commented/removed. | ||
77 | DDetail = true; | ||
78 | } | ||
79 | |||
80 | public void Dispose() | ||
81 | { | ||
82 | // TODO!!!!!!!!! | ||
83 | } | ||
84 | |||
85 | // Callbacks called just before either the body or shape is destroyed. | ||
86 | // Mostly used for changing bodies out from under Linksets. | ||
87 | // Useful for other cases where parameters need saving. | ||
88 | // Passing 'null' says no callback. | ||
89 | public delegate void ShapeDestructionCallback(BulletShape shape); | ||
90 | public delegate void BodyDestructionCallback(BulletBody body); | ||
91 | |||
92 | // Called to update/change the body and shape for an object. | ||
93 | // First checks the shape and updates that if necessary then makes | ||
94 | // sure the body is of the right type. | ||
95 | // Return 'true' if either the body or the shape changed. | ||
96 | // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before | ||
97 | // the current shape or body is destroyed. This allows the caller to remove any | ||
98 | // higher level dependencies on the shape or body. Mostly used for LinkSets to | ||
99 | // remove the physical constraints before the body is destroyed. | ||
100 | // Called at taint-time!! | ||
101 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, | ||
102 | ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) | ||
103 | { | ||
104 | PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); | ||
105 | |||
106 | bool ret = false; | ||
107 | |||
108 | // This lock could probably be pushed down lower but building shouldn't take long | ||
109 | lock (m_collectionActivityLock) | ||
110 | { | ||
111 | // Do we have the correct geometry for this type of object? | ||
112 | // Updates prim.BSShape with information/pointers to shape. | ||
113 | // Returns 'true' of BSShape is changed to a new shape. | ||
114 | bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback); | ||
115 | // If we had to select a new shape geometry for the object, | ||
116 | // rebuild the body around it. | ||
117 | // Updates prim.BSBody with information/pointers to requested body | ||
118 | // Returns 'true' if BSBody was changed. | ||
119 | bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, | ||
120 | prim.PhysShape, bodyCallback); | ||
121 | ret = newGeom || newBody; | ||
122 | } | ||
123 | DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", | ||
124 | prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape); | ||
125 | |||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) | ||
130 | { | ||
131 | return GetBodyAndShape(forceRebuild, sim, prim, null, null); | ||
132 | } | ||
133 | |||
134 | // Track another user of a body. | ||
135 | // We presume the caller has allocated the body. | ||
136 | // Bodies only have one user so the body is just put into the world if not already there. | ||
137 | public void ReferenceBody(BulletBody body, bool inTaintTime) | ||
138 | { | ||
139 | lock (m_collectionActivityLock) | ||
140 | { | ||
141 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); | ||
142 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() | ||
143 | { | ||
144 | if (!BulletSimAPI.IsInWorld2(PhysicsScene.World.ptr, body.ptr)) | ||
145 | { | ||
146 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); | ||
147 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); | ||
148 | } | ||
149 | }); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | // Release the usage of a body. | ||
154 | // Called when releasing use of a BSBody. BSShape is handled separately. | ||
155 | public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) | ||
156 | { | ||
157 | if (!body.HasPhysicalBody) | ||
158 | return; | ||
159 | |||
160 | lock (m_collectionActivityLock) | ||
161 | { | ||
162 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() | ||
163 | { | ||
164 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", | ||
165 | body.ID, body, inTaintTime); | ||
166 | // If the caller needs to know the old body is going away, pass the event up. | ||
167 | if (bodyCallback != null) bodyCallback(body); | ||
168 | |||
169 | if (BulletSimAPI.IsInWorld2(PhysicsScene.World.ptr, body.ptr)) | ||
170 | { | ||
171 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); | ||
172 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); | ||
173 | } | ||
174 | |||
175 | // Zero any reference to the shape so it is not freed when the body is deleted. | ||
176 | BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, null); | ||
177 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); | ||
178 | }); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | // Track the datastructures and use count for a shape. | ||
183 | // When creating a hull, this is called first to reference the mesh | ||
184 | // and then again to reference the hull. | ||
185 | // Meshes and hulls for the same shape have the same hash key. | ||
186 | // NOTE that native shapes are not added to the mesh list or removed. | ||
187 | // Returns 'true' if this is the initial reference to the shape. Otherwise reused. | ||
188 | public bool ReferenceShape(BulletShape shape) | ||
189 | { | ||
190 | bool ret = false; | ||
191 | switch (shape.type) | ||
192 | { | ||
193 | case BSPhysicsShapeType.SHAPE_MESH: | ||
194 | MeshDesc meshDesc; | ||
195 | if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) | ||
196 | { | ||
197 | // There is an existing instance of this mesh. | ||
198 | meshDesc.referenceCount++; | ||
199 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", | ||
200 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | // This is a new reference to a mesh | ||
205 | meshDesc.ptr = shape.ptr; | ||
206 | meshDesc.shapeKey = shape.shapeKey; | ||
207 | // We keep a reference to the underlying IMesh data so a hull can be built | ||
208 | meshDesc.referenceCount = 1; | ||
209 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", | ||
210 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | ||
211 | ret = true; | ||
212 | } | ||
213 | meshDesc.lastReferenced = System.DateTime.Now; | ||
214 | Meshes[shape.shapeKey] = meshDesc; | ||
215 | break; | ||
216 | case BSPhysicsShapeType.SHAPE_HULL: | ||
217 | HullDesc hullDesc; | ||
218 | if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) | ||
219 | { | ||
220 | // There is an existing instance of this hull. | ||
221 | hullDesc.referenceCount++; | ||
222 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", | ||
223 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | ||
224 | } | ||
225 | else | ||
226 | { | ||
227 | // This is a new reference to a hull | ||
228 | hullDesc.ptr = shape.ptr; | ||
229 | hullDesc.shapeKey = shape.shapeKey; | ||
230 | hullDesc.referenceCount = 1; | ||
231 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", | ||
232 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | ||
233 | ret = true; | ||
234 | |||
235 | } | ||
236 | hullDesc.lastReferenced = System.DateTime.Now; | ||
237 | Hulls[shape.shapeKey] = hullDesc; | ||
238 | break; | ||
239 | case BSPhysicsShapeType.SHAPE_UNKNOWN: | ||
240 | break; | ||
241 | default: | ||
242 | // Native shapes are not tracked and they don't go into any list | ||
243 | break; | ||
244 | } | ||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | // Release the usage of a shape. | ||
249 | public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) | ||
250 | { | ||
251 | if (!shape.HasPhysicalShape) | ||
252 | return; | ||
253 | |||
254 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() | ||
255 | { | ||
256 | if (shape.HasPhysicalShape) | ||
257 | { | ||
258 | if (shape.isNativeShape) | ||
259 | { | ||
260 | // Native shapes are not tracked and are released immediately | ||
261 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", | ||
262 | BSScene.DetailLogZero, shape.ptr.ToString(), inTaintTime); | ||
263 | if (shapeCallback != null) shapeCallback(shape); | ||
264 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | ||
265 | } | ||
266 | else | ||
267 | { | ||
268 | switch (shape.type) | ||
269 | { | ||
270 | case BSPhysicsShapeType.SHAPE_HULL: | ||
271 | DereferenceHull(shape, shapeCallback); | ||
272 | break; | ||
273 | case BSPhysicsShapeType.SHAPE_MESH: | ||
274 | DereferenceMesh(shape, shapeCallback); | ||
275 | break; | ||
276 | case BSPhysicsShapeType.SHAPE_COMPOUND: | ||
277 | DereferenceCompound(shape, shapeCallback); | ||
278 | break; | ||
279 | case BSPhysicsShapeType.SHAPE_UNKNOWN: | ||
280 | break; | ||
281 | default: | ||
282 | break; | ||
283 | } | ||
284 | } | ||
285 | } | ||
286 | }); | ||
287 | } | ||
288 | |||
289 | // Count down the reference count for a mesh shape | ||
290 | // Called at taint-time. | ||
291 | private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback) | ||
292 | { | ||
293 | MeshDesc meshDesc; | ||
294 | if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) | ||
295 | { | ||
296 | meshDesc.referenceCount--; | ||
297 | // TODO: release the Bullet storage | ||
298 | if (shapeCallback != null) shapeCallback(shape); | ||
299 | meshDesc.lastReferenced = System.DateTime.Now; | ||
300 | Meshes[shape.shapeKey] = meshDesc; | ||
301 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", | ||
302 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); | ||
303 | |||
304 | } | ||
305 | } | ||
306 | |||
307 | // Count down the reference count for a hull shape | ||
308 | // Called at taint-time. | ||
309 | private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback) | ||
310 | { | ||
311 | HullDesc hullDesc; | ||
312 | if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) | ||
313 | { | ||
314 | hullDesc.referenceCount--; | ||
315 | // TODO: release the Bullet storage (aging old entries?) | ||
316 | |||
317 | // Tell upper layers that, if they have dependencies on this shape, this link is going away | ||
318 | if (shapeCallback != null) shapeCallback(shape); | ||
319 | |||
320 | hullDesc.lastReferenced = System.DateTime.Now; | ||
321 | Hulls[shape.shapeKey] = hullDesc; | ||
322 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", | ||
323 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | // Remove a reference to a compound shape. | ||
328 | // Taking a compound shape apart is a little tricky because if you just delete the | ||
329 | // physical shape, it will free all the underlying children. We can't do that because | ||
330 | // they could be shared. So, this removes each of the children from the compound and | ||
331 | // dereferences them separately before destroying the compound collision object itself. | ||
332 | // Called at taint-time. | ||
333 | private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) | ||
334 | { | ||
335 | if (!BulletSimAPI.IsCompound2(shape.ptr)) | ||
336 | { | ||
337 | // Failed the sanity check!! | ||
338 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | ||
339 | LogHeader, shape.type, shape.ptr.ToString()); | ||
340 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | ||
341 | BSScene.DetailLogZero, shape.type, shape.ptr.ToString()); | ||
342 | return; | ||
343 | } | ||
344 | |||
345 | int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); | ||
346 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); | ||
347 | |||
348 | for (int ii = numChildren - 1; ii >= 0; ii--) | ||
349 | { | ||
350 | Object childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii); | ||
351 | DereferenceAnonCollisionShape(childShape); | ||
352 | } | ||
353 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | ||
354 | } | ||
355 | |||
356 | // Sometimes we have a pointer to a collision shape but don't know what type it is. | ||
357 | // Figure out type and call the correct dereference routine. | ||
358 | // Called at taint-time. | ||
359 | private void DereferenceAnonCollisionShape(Object cShape) | ||
360 | { | ||
361 | MeshDesc meshDesc; | ||
362 | HullDesc hullDesc; | ||
363 | |||
364 | BulletShape shapeInfo = new BulletShape(cShape); | ||
365 | if (TryGetMeshByPtr(cShape, out meshDesc)) | ||
366 | { | ||
367 | shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; | ||
368 | shapeInfo.shapeKey = meshDesc.shapeKey; | ||
369 | } | ||
370 | else | ||
371 | { | ||
372 | if (TryGetHullByPtr(cShape, out hullDesc)) | ||
373 | { | ||
374 | shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; | ||
375 | shapeInfo.shapeKey = hullDesc.shapeKey; | ||
376 | } | ||
377 | else | ||
378 | { | ||
379 | if (BulletSimAPI.IsCompound2(cShape)) | ||
380 | { | ||
381 | shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; | ||
382 | } | ||
383 | else | ||
384 | { | ||
385 | if (BulletSimAPI.IsNativeShape2(cShape)) | ||
386 | { | ||
387 | shapeInfo.isNativeShape = true; | ||
388 | shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) | ||
389 | } | ||
390 | } | ||
391 | } | ||
392 | } | ||
393 | |||
394 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); | ||
395 | |||
396 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) | ||
397 | { | ||
398 | DereferenceShape(shapeInfo, true, null); | ||
399 | } | ||
400 | else | ||
401 | { | ||
402 | PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", | ||
403 | LogHeader, PhysicsScene.RegionName, cShape.ToString()); | ||
404 | } | ||
405 | } | ||
406 | |||
407 | // Create the geometry information in Bullet for later use. | ||
408 | // The objects needs a hull if it's physical otherwise a mesh is enough. | ||
409 | // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls, | ||
410 | // shared geometries will be used. If the parameters of the existing shape are the same | ||
411 | // as this request, the shape is not rebuilt. | ||
412 | // Info in prim.BSShape is updated to the new shape. | ||
413 | // Returns 'true' if the geometry was rebuilt. | ||
414 | // Called at taint-time! | ||
415 | private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
416 | { | ||
417 | bool ret = false; | ||
418 | bool haveShape = false; | ||
419 | |||
420 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) | ||
421 | { | ||
422 | // an avatar capsule is close to a native shape (it is not shared) | ||
423 | GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, | ||
424 | FixedShapeKey.KEY_CAPSULE, shapeCallback); | ||
425 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); | ||
426 | ret = true; | ||
427 | haveShape = true; | ||
428 | } | ||
429 | |||
430 | // Compound shapes are handled special as they are rebuilt from scratch. | ||
431 | // This isn't too great a hardship since most of the child shapes will have already been created. | ||
432 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) | ||
433 | { | ||
434 | ret = GetReferenceToCompoundShape(prim, shapeCallback); | ||
435 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); | ||
436 | haveShape = true; | ||
437 | } | ||
438 | |||
439 | if (!haveShape) | ||
440 | { | ||
441 | ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback); | ||
442 | } | ||
443 | |||
444 | return ret; | ||
445 | } | ||
446 | |||
447 | // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. | ||
448 | public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
449 | { | ||
450 | bool ret = false; | ||
451 | bool haveShape = false; | ||
452 | bool nativeShapePossible = true; | ||
453 | PrimitiveBaseShape pbs = prim.BaseShape; | ||
454 | |||
455 | // If the prim attributes are simple, this could be a simple Bullet native shape | ||
456 | if (!haveShape | ||
457 | && pbs != null | ||
458 | && nativeShapePossible | ||
459 | && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) | ||
460 | || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | ||
461 | && pbs.ProfileHollow == 0 | ||
462 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | ||
463 | && pbs.PathBegin == 0 && pbs.PathEnd == 0 | ||
464 | && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 | ||
465 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | ||
466 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) | ||
467 | { | ||
468 | // Get the scale of any existing shape so we can see if the new shape is same native type and same size. | ||
469 | OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; | ||
470 | if (prim.PhysShape.HasPhysicalShape) | ||
471 | scaleOfExistingShape = BulletSimAPI.GetLocalScaling2(prim.PhysShape.ptr); | ||
472 | |||
473 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", | ||
474 | prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); | ||
475 | |||
476 | // It doesn't look like Bullet scales spheres so make sure the scales are all equal | ||
477 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | ||
478 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) | ||
479 | { | ||
480 | haveShape = true; | ||
481 | if (forceRebuild | ||
482 | || prim.Scale != scaleOfExistingShape | ||
483 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE | ||
484 | ) | ||
485 | { | ||
486 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, | ||
487 | FixedShapeKey.KEY_SPHERE, shapeCallback); | ||
488 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", | ||
489 | prim.LocalID, forceRebuild, prim.PhysShape); | ||
490 | } | ||
491 | } | ||
492 | if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) | ||
493 | { | ||
494 | haveShape = true; | ||
495 | if (forceRebuild | ||
496 | || prim.Scale != scaleOfExistingShape | ||
497 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX | ||
498 | ) | ||
499 | { | ||
500 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, | ||
501 | FixedShapeKey.KEY_BOX, shapeCallback); | ||
502 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", | ||
503 | prim.LocalID, forceRebuild, prim.PhysShape); | ||
504 | } | ||
505 | } | ||
506 | } | ||
507 | |||
508 | // If a simple shape is not happening, create a mesh and possibly a hull. | ||
509 | if (!haveShape && pbs != null) | ||
510 | { | ||
511 | ret = CreateGeomMeshOrHull(prim, shapeCallback); | ||
512 | } | ||
513 | |||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
518 | { | ||
519 | |||
520 | bool ret = false; | ||
521 | // Note that if it's a native shape, the check for physical/non-physical is not | ||
522 | // made. Native shapes work in either case. | ||
523 | if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) | ||
524 | { | ||
525 | // Update prim.BSShape to reference a hull of this shape. | ||
526 | ret = GetReferenceToHull(prim,shapeCallback); | ||
527 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", | ||
528 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | ||
529 | } | ||
530 | else | ||
531 | { | ||
532 | ret = GetReferenceToMesh(prim, shapeCallback); | ||
533 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", | ||
534 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | ||
535 | } | ||
536 | return ret; | ||
537 | } | ||
538 | |||
539 | // Creates a native shape and assignes it to prim.BSShape. | ||
540 | // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). | ||
541 | private bool GetReferenceToNativeShape(BSPhysObject prim, | ||
542 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey, | ||
543 | ShapeDestructionCallback shapeCallback) | ||
544 | { | ||
545 | // release any previous shape | ||
546 | DereferenceShape(prim.PhysShape, true, shapeCallback); | ||
547 | |||
548 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); | ||
549 | |||
550 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. | ||
551 | if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", | ||
552 | prim.LocalID, newShape, prim.Scale); | ||
553 | |||
554 | // native shapes are scaled by Bullet | ||
555 | prim.PhysShape = newShape; | ||
556 | return true; | ||
557 | } | ||
558 | |||
559 | private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType, | ||
560 | FixedShapeKey shapeKey) | ||
561 | { | ||
562 | BulletShape newShape; | ||
563 | // Need to make sure the passed shape information is for the native type. | ||
564 | ShapeData nativeShapeData = new ShapeData(); | ||
565 | nativeShapeData.Type = shapeType; | ||
566 | nativeShapeData.ID = prim.LocalID; | ||
567 | nativeShapeData.Scale = prim.Scale; | ||
568 | nativeShapeData.Size = prim.Scale; // unneeded, I think. | ||
569 | nativeShapeData.MeshKey = (ulong)shapeKey; | ||
570 | nativeShapeData.HullKey = (ulong)shapeKey; | ||
571 | |||
572 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) | ||
573 | { | ||
574 | // The proper scale has been calculated in the prim. | ||
575 | newShape = new BulletShape( | ||
576 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) | ||
577 | , shapeType); | ||
578 | if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | ||
579 | } | ||
580 | else | ||
581 | { | ||
582 | // Native shapes are scaled in Bullet so set the scaling to the size | ||
583 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); | ||
584 | } | ||
585 | if (!newShape.HasPhysicalShape) | ||
586 | { | ||
587 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | ||
588 | LogHeader, prim.LocalID, shapeType); | ||
589 | } | ||
590 | newShape.shapeKey = (System.UInt64)shapeKey; | ||
591 | newShape.isNativeShape = true; | ||
592 | |||
593 | return newShape; | ||
594 | } | ||
595 | |||
596 | // Builds a mesh shape in the physical world and updates prim.BSShape. | ||
597 | // Dereferences previous shape in BSShape and adds a reference for this new shape. | ||
598 | // Returns 'true' of a mesh was actually built. Otherwise . | ||
599 | // Called at taint-time! | ||
600 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
601 | { | ||
602 | BulletShape newShape = new BulletShape(); | ||
603 | |||
604 | float lod; | ||
605 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
606 | |||
607 | // if this new shape is the same as last time, don't recreate the mesh | ||
608 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) | ||
609 | return false; | ||
610 | |||
611 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", | ||
612 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); | ||
613 | |||
614 | // Since we're recreating new, get rid of the reference to the previous shape | ||
615 | DereferenceShape(prim.PhysShape, true, shapeCallback); | ||
616 | |||
617 | newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); | ||
618 | // Take evasive action if the mesh was not constructed. | ||
619 | newShape = VerifyMeshCreated(newShape, prim); | ||
620 | |||
621 | ReferenceShape(newShape); | ||
622 | |||
623 | prim.PhysShape = newShape; | ||
624 | |||
625 | return true; // 'true' means a new shape has been added to this prim | ||
626 | } | ||
627 | |||
628 | private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
629 | { | ||
630 | IMesh meshData = null; | ||
631 | Object meshPtr = null; | ||
632 | MeshDesc meshDesc; | ||
633 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) | ||
634 | { | ||
635 | // If the mesh has already been built just use it. | ||
636 | meshPtr = meshDesc.ptr; | ||
637 | } | ||
638 | else | ||
639 | { | ||
640 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); | ||
641 | |||
642 | if (meshData != null) | ||
643 | { | ||
644 | int[] indices = meshData.getIndexListAsInt(); | ||
645 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
646 | |||
647 | float[] verticesAsFloats = new float[vertices.Count * 3]; | ||
648 | int vi = 0; | ||
649 | foreach (OMV.Vector3 vv in vertices) | ||
650 | { | ||
651 | verticesAsFloats[vi++] = vv.X; | ||
652 | verticesAsFloats[vi++] = vv.Y; | ||
653 | verticesAsFloats[vi++] = vv.Z; | ||
654 | } | ||
655 | |||
656 | // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | ||
657 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); | ||
658 | |||
659 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | ||
660 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); | ||
661 | } | ||
662 | } | ||
663 | BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH); | ||
664 | newShape.shapeKey = newMeshKey; | ||
665 | |||
666 | return newShape; | ||
667 | } | ||
668 | |||
669 | // See that hull shape exists in the physical world and update prim.BSShape. | ||
670 | // We could be creating the hull because scale changed or whatever. | ||
671 | private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
672 | { | ||
673 | BulletShape newShape; | ||
674 | |||
675 | float lod; | ||
676 | System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
677 | |||
678 | // if the hull hasn't changed, don't rebuild it | ||
679 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) | ||
680 | return false; | ||
681 | |||
682 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", | ||
683 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); | ||
684 | |||
685 | // Remove usage of the previous shape. | ||
686 | DereferenceShape(prim.PhysShape, true, shapeCallback); | ||
687 | |||
688 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); | ||
689 | newShape = VerifyMeshCreated(newShape, prim); | ||
690 | |||
691 | ReferenceShape(newShape); | ||
692 | |||
693 | prim.PhysShape = newShape; | ||
694 | return true; // 'true' means a new shape has been added to this prim | ||
695 | } | ||
696 | |||
697 | List<ConvexResult> m_hulls; | ||
698 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
699 | { | ||
700 | |||
701 | Object hullPtr = null; | ||
702 | HullDesc hullDesc; | ||
703 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) | ||
704 | { | ||
705 | // If the hull shape already is created, just use it. | ||
706 | hullPtr = hullDesc.ptr; | ||
707 | } | ||
708 | else | ||
709 | { | ||
710 | // Build a new hull in the physical world | ||
711 | // Pass true for physicalness as this creates some sort of bounding box which we don't need | ||
712 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); | ||
713 | if (meshData != null) | ||
714 | { | ||
715 | |||
716 | int[] indices = meshData.getIndexListAsInt(); | ||
717 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
718 | |||
719 | //format conversion from IMesh format to DecompDesc format | ||
720 | List<int> convIndices = new List<int>(); | ||
721 | List<float3> convVertices = new List<float3>(); | ||
722 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
723 | { | ||
724 | convIndices.Add(indices[ii]); | ||
725 | } | ||
726 | foreach (OMV.Vector3 vv in vertices) | ||
727 | { | ||
728 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
729 | } | ||
730 | |||
731 | // setup and do convex hull conversion | ||
732 | m_hulls = new List<ConvexResult>(); | ||
733 | DecompDesc dcomp = new DecompDesc(); | ||
734 | dcomp.mIndices = convIndices; | ||
735 | dcomp.mVertices = convVertices; | ||
736 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
737 | // create the hull into the _hulls variable | ||
738 | convexBuilder.process(dcomp); | ||
739 | |||
740 | // Convert the vertices and indices for passing to unmanaged. | ||
741 | // The hull information is passed as a large floating point array. | ||
742 | // The format is: | ||
743 | // convHulls[0] = number of hulls | ||
744 | // convHulls[1] = number of vertices in first hull | ||
745 | // convHulls[2] = hull centroid X coordinate | ||
746 | // convHulls[3] = hull centroid Y coordinate | ||
747 | // convHulls[4] = hull centroid Z coordinate | ||
748 | // convHulls[5] = first hull vertex X | ||
749 | // convHulls[6] = first hull vertex Y | ||
750 | // convHulls[7] = first hull vertex Z | ||
751 | // convHulls[8] = second hull vertex X | ||
752 | // ... | ||
753 | // convHulls[n] = number of vertices in second hull | ||
754 | // convHulls[n+1] = second hull centroid X coordinate | ||
755 | // ... | ||
756 | // | ||
757 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
758 | // data structures that do not need to be converted in order to pass to Bullet. | ||
759 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
760 | int hullCount = m_hulls.Count; | ||
761 | int totalVertices = 1; // include one for the count of the hulls | ||
762 | foreach (ConvexResult cr in m_hulls) | ||
763 | { | ||
764 | totalVertices += 4; // add four for the vertex count and centroid | ||
765 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
766 | } | ||
767 | float[] convHulls = new float[totalVertices]; | ||
768 | |||
769 | convHulls[0] = (float)hullCount; | ||
770 | int jj = 1; | ||
771 | foreach (ConvexResult cr in m_hulls) | ||
772 | { | ||
773 | // copy vertices for index access | ||
774 | float3[] verts = new float3[cr.HullVertices.Count]; | ||
775 | int kk = 0; | ||
776 | foreach (float3 ff in cr.HullVertices) | ||
777 | { | ||
778 | verts[kk++] = ff; | ||
779 | } | ||
780 | |||
781 | // add to the array one hull's worth of data | ||
782 | convHulls[jj++] = cr.HullIndices.Count; | ||
783 | convHulls[jj++] = 0f; // centroid x,y,z | ||
784 | convHulls[jj++] = 0f; | ||
785 | convHulls[jj++] = 0f; | ||
786 | foreach (int ind in cr.HullIndices) | ||
787 | { | ||
788 | convHulls[jj++] = verts[ind].x; | ||
789 | convHulls[jj++] = verts[ind].y; | ||
790 | convHulls[jj++] = verts[ind].z; | ||
791 | } | ||
792 | } | ||
793 | // create the hull data structure in Bullet | ||
794 | hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); | ||
795 | } | ||
796 | } | ||
797 | |||
798 | BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL); | ||
799 | newShape.shapeKey = newHullKey; | ||
800 | |||
801 | return newShape; | ||
802 | } | ||
803 | |||
804 | // Callback from convex hull creater with a newly created hull. | ||
805 | // Just add it to our collection of hulls for this shape. | ||
806 | private void HullReturn(ConvexResult result) | ||
807 | { | ||
808 | m_hulls.Add(result); | ||
809 | return; | ||
810 | } | ||
811 | |||
812 | // Compound shapes are always built from scratch. | ||
813 | // This shouldn't be to bad since most of the parts will be meshes that had been built previously. | ||
814 | private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
815 | { | ||
816 | // Remove reference to the old shape | ||
817 | // Don't need to do this as the shape is freed when the new root shape is created below. | ||
818 | // DereferenceShape(prim.PhysShape, true, shapeCallback); | ||
819 | |||
820 | BulletShape cShape = new BulletShape( | ||
821 | BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND); | ||
822 | |||
823 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. | ||
824 | CreateGeomMeshOrHull(prim, shapeCallback); | ||
825 | BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); | ||
826 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", | ||
827 | prim.LocalID, cShape, prim.PhysShape); | ||
828 | |||
829 | prim.PhysShape = cShape; | ||
830 | |||
831 | return true; | ||
832 | } | ||
833 | |||
834 | // Create a hash of all the shape parameters to be used as a key | ||
835 | // for this particular shape. | ||
836 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) | ||
837 | { | ||
838 | // level of detail based on size and type of the object | ||
839 | float lod = BSParam.MeshLOD; | ||
840 | if (pbs.SculptEntry) | ||
841 | lod = BSParam.SculptLOD; | ||
842 | |||
843 | // Mega prims usually get more detail because one can interact with shape approximations at this size. | ||
844 | float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); | ||
845 | if (maxAxis > BSParam.MeshMegaPrimThreshold) | ||
846 | lod = BSParam.MeshMegaPrimLOD; | ||
847 | |||
848 | retLod = lod; | ||
849 | return pbs.GetMeshKey(size, lod); | ||
850 | } | ||
851 | // For those who don't want the LOD | ||
852 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs) | ||
853 | { | ||
854 | float lod; | ||
855 | return ComputeShapeKey(size, pbs, out lod); | ||
856 | } | ||
857 | |||
858 | // The creation of a mesh or hull can fail if an underlying asset is not available. | ||
859 | // There are two cases: 1) the asset is not in the cache and it needs to be fetched; | ||
860 | // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). | ||
861 | // The first case causes the asset to be fetched. The second case requires | ||
862 | // us to not loop forever. | ||
863 | // Called after creating a physical mesh or hull. If the physical shape was created, | ||
864 | // just return. | ||
865 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) | ||
866 | { | ||
867 | // If the shape was successfully created, nothing more to do | ||
868 | if (newShape.HasPhysicalShape) | ||
869 | return newShape; | ||
870 | |||
871 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | ||
872 | if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) | ||
873 | { | ||
874 | prim.LastAssetBuildFailed = true; | ||
875 | BSPhysObject xprim = prim; | ||
876 | DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", | ||
877 | LogHeader, prim.LocalID, prim.LastAssetBuildFailed); | ||
878 | Util.FireAndForget(delegate | ||
879 | { | ||
880 | RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; | ||
881 | if (assetProvider != null) | ||
882 | { | ||
883 | BSPhysObject yprim = xprim; // probably not necessary, but, just in case. | ||
884 | assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) | ||
885 | { | ||
886 | if (!yprim.BaseShape.SculptEntry) | ||
887 | return; | ||
888 | if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) | ||
889 | return; | ||
890 | |||
891 | yprim.BaseShape.SculptData = asset.Data; | ||
892 | // This will cause the prim to see that the filler shape is not the right | ||
893 | // one and try again to build the object. | ||
894 | // No race condition with the normal shape setting since the rebuild is at taint time. | ||
895 | yprim.ForceBodyShapeRebuild(false); | ||
896 | |||
897 | }); | ||
898 | } | ||
899 | }); | ||
900 | } | ||
901 | else | ||
902 | { | ||
903 | if (prim.LastAssetBuildFailed) | ||
904 | { | ||
905 | PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", | ||
906 | LogHeader, prim.LocalID, prim.BaseShape.SculptTexture); | ||
907 | } | ||
908 | } | ||
909 | |||
910 | // While we figure out the real problem, stick a simple native shape on the object. | ||
911 | BulletShape fillinShape = | ||
912 | BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | ||
913 | |||
914 | return fillinShape; | ||
915 | } | ||
916 | |||
917 | // Create a body object in Bullet. | ||
918 | // Updates prim.BSBody with the information about the new body if one is created. | ||
919 | // Returns 'true' if an object was actually created. | ||
920 | // Called at taint-time. | ||
921 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BulletShape shape, | ||
922 | BodyDestructionCallback bodyCallback) | ||
923 | { | ||
924 | bool ret = false; | ||
925 | |||
926 | // the mesh, hull or native shape must have already been created in Bullet | ||
927 | bool mustRebuild = !prim.PhysBody.HasPhysicalBody; | ||
928 | |||
929 | // If there is an existing body, verify it's of an acceptable type. | ||
930 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. | ||
931 | if (!mustRebuild) | ||
932 | { | ||
933 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr); | ||
934 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY | ||
935 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) | ||
936 | { | ||
937 | // If the collisionObject is not the correct type for solidness, rebuild what's there | ||
938 | mustRebuild = true; | ||
939 | } | ||
940 | } | ||
941 | |||
942 | if (mustRebuild || forceRebuild) | ||
943 | { | ||
944 | // Free any old body | ||
945 | DereferenceBody(prim.PhysBody, true, bodyCallback); | ||
946 | |||
947 | BulletBody aBody; | ||
948 | Object bodyPtr = null; | ||
949 | if (prim.IsSolid) | ||
950 | { | ||
951 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, | ||
952 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | ||
953 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString()); | ||
954 | } | ||
955 | else | ||
956 | { | ||
957 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, | ||
958 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | ||
959 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString()); | ||
960 | } | ||
961 | aBody = new BulletBody(prim.LocalID, bodyPtr); | ||
962 | |||
963 | ReferenceBody(aBody, true); | ||
964 | |||
965 | prim.PhysBody = aBody; | ||
966 | |||
967 | ret = true; | ||
968 | } | ||
969 | |||
970 | return ret; | ||
971 | } | ||
972 | |||
973 | private bool TryGetMeshByPtr(Object addr, out MeshDesc outDesc) | ||
974 | { | ||
975 | bool ret = false; | ||
976 | MeshDesc foundDesc = new MeshDesc(); | ||
977 | foreach (MeshDesc md in Meshes.Values) | ||
978 | { | ||
979 | if (md.ptr == addr) | ||
980 | { | ||
981 | foundDesc = md; | ||
982 | ret = true; | ||
983 | break; | ||
984 | } | ||
985 | |||
986 | } | ||
987 | outDesc = foundDesc; | ||
988 | return ret; | ||
989 | } | ||
990 | |||
991 | private bool TryGetHullByPtr(Object addr, out HullDesc outDesc) | ||
992 | { | ||
993 | bool ret = false; | ||
994 | HullDesc foundDesc = new HullDesc(); | ||
995 | foreach (HullDesc hd in Hulls.Values) | ||
996 | { | ||
997 | if (hd.ptr == addr) | ||
998 | { | ||
999 | foundDesc = hd; | ||
1000 | ret = true; | ||
1001 | break; | ||
1002 | } | ||
1003 | |||
1004 | } | ||
1005 | outDesc = foundDesc; | ||
1006 | return ret; | ||
1007 | } | ||
1008 | |||
1009 | private void DetailLog(string msg, params Object[] args) | ||
1010 | { | ||
1011 | if (PhysicsScene.PhysicsLogging.Enabled) | ||
1012 | PhysicsScene.DetailLog(msg, args); | ||
1013 | } | ||
1014 | } | ||
1015 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs new file mode 100644 index 0000000..8ff0275 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs | |||
@@ -0,0 +1,208 @@ | |||
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 | namespace OpenSim.Region.Physics.BulletSNPlugin | ||
34 | { | ||
35 | public abstract class BSShape | ||
36 | { | ||
37 | public Object ptr { get; set; } | ||
38 | public BSPhysicsShapeType type { get; set; } | ||
39 | public System.UInt64 key { get; set; } | ||
40 | public int referenceCount { get; set; } | ||
41 | public DateTime lastReferenced { get; set; } | ||
42 | |||
43 | public BSShape() | ||
44 | { | ||
45 | ptr = null; | ||
46 | type = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
47 | key = 0; | ||
48 | referenceCount = 0; | ||
49 | lastReferenced = DateTime.Now; | ||
50 | } | ||
51 | |||
52 | // Get a reference to a physical shape. Create if it doesn't exist | ||
53 | public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
54 | { | ||
55 | BSShape ret = null; | ||
56 | |||
57 | if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) | ||
58 | { | ||
59 | // an avatar capsule is close to a native shape (it is not shared) | ||
60 | ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE, | ||
61 | FixedShapeKey.KEY_CAPSULE); | ||
62 | physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret); | ||
63 | } | ||
64 | |||
65 | // Compound shapes are handled special as they are rebuilt from scratch. | ||
66 | // This isn't too great a hardship since most of the child shapes will already been created. | ||
67 | if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) | ||
68 | { | ||
69 | // Getting a reference to a compound shape gets you the compound shape with the root prim shape added | ||
70 | ret = BSShapeCompound.GetReference(prim); | ||
71 | physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret); | ||
72 | } | ||
73 | |||
74 | if (ret == null) | ||
75 | ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); | ||
76 | |||
77 | return ret; | ||
78 | } | ||
79 | public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
80 | { | ||
81 | return null; | ||
82 | } | ||
83 | public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
84 | { | ||
85 | return null; | ||
86 | } | ||
87 | |||
88 | // Release the use of a physical shape. | ||
89 | public abstract void Dereference(BSScene physicsScene); | ||
90 | |||
91 | // All shapes have a static call to get a reference to the physical shape | ||
92 | // protected abstract static BSShape GetReference(); | ||
93 | |||
94 | public override string ToString() | ||
95 | { | ||
96 | StringBuilder buff = new StringBuilder(); | ||
97 | buff.Append("<p="); | ||
98 | buff.Append(ptr.ToString()); | ||
99 | buff.Append(",s="); | ||
100 | buff.Append(type.ToString()); | ||
101 | buff.Append(",k="); | ||
102 | buff.Append(key.ToString("X")); | ||
103 | buff.Append(",c="); | ||
104 | buff.Append(referenceCount.ToString()); | ||
105 | buff.Append(">"); | ||
106 | return buff.ToString(); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | public class BSShapeNull : BSShape | ||
111 | { | ||
112 | public BSShapeNull() : base() | ||
113 | { | ||
114 | } | ||
115 | public static BSShape GetReference() { return new BSShapeNull(); } | ||
116 | public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } | ||
117 | } | ||
118 | |||
119 | public class BSShapeNative : BSShape | ||
120 | { | ||
121 | private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; | ||
122 | public BSShapeNative() : base() | ||
123 | { | ||
124 | } | ||
125 | public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, | ||
126 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | ||
127 | { | ||
128 | // Native shapes are not shared and are always built anew. | ||
129 | return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); | ||
130 | } | ||
131 | |||
132 | private BSShapeNative(BSScene physicsScene, BSPhysObject prim, | ||
133 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | ||
134 | { | ||
135 | ShapeData nativeShapeData = new ShapeData(); | ||
136 | nativeShapeData.Type = shapeType; | ||
137 | nativeShapeData.ID = prim.LocalID; | ||
138 | nativeShapeData.Scale = prim.Scale; | ||
139 | nativeShapeData.Size = prim.Scale; | ||
140 | nativeShapeData.MeshKey = (ulong)shapeKey; | ||
141 | nativeShapeData.HullKey = (ulong)shapeKey; | ||
142 | |||
143 | |||
144 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) | ||
145 | { | ||
146 | ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale); | ||
147 | physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | ||
148 | } | ||
149 | else | ||
150 | { | ||
151 | ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData); | ||
152 | } | ||
153 | if (ptr == null) | ||
154 | { | ||
155 | physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | ||
156 | LogHeader, prim.LocalID, shapeType); | ||
157 | } | ||
158 | type = shapeType; | ||
159 | key = (UInt64)shapeKey; | ||
160 | } | ||
161 | // Make this reference to the physical shape go away since native shapes are not shared. | ||
162 | public override void Dereference(BSScene physicsScene) | ||
163 | { | ||
164 | // Native shapes are not tracked and are released immediately | ||
165 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); | ||
166 | BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr); | ||
167 | ptr = null; | ||
168 | // Garbage collection will free up this instance. | ||
169 | } | ||
170 | } | ||
171 | |||
172 | public class BSShapeMesh : BSShape | ||
173 | { | ||
174 | private static string LogHeader = "[BULLETSIM SHAPE MESH]"; | ||
175 | private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>(); | ||
176 | |||
177 | public BSShapeMesh() : base() | ||
178 | { | ||
179 | } | ||
180 | public static BSShape GetReference() { return new BSShapeNull(); } | ||
181 | public override void Dereference(BSScene physicsScene) { } | ||
182 | } | ||
183 | |||
184 | public class BSShapeHull : BSShape | ||
185 | { | ||
186 | private static string LogHeader = "[BULLETSIM SHAPE HULL]"; | ||
187 | private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); | ||
188 | |||
189 | public BSShapeHull() : base() | ||
190 | { | ||
191 | } | ||
192 | public static BSShape GetReference() { return new BSShapeNull(); } | ||
193 | public override void Dereference(BSScene physicsScene) { } | ||
194 | } | ||
195 | |||
196 | public class BSShapeCompound : BSShape | ||
197 | { | ||
198 | private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; | ||
199 | public BSShapeCompound() : base() | ||
200 | { | ||
201 | } | ||
202 | public static BSShape GetReference(BSPhysObject prim) | ||
203 | { | ||
204 | return new BSShapeNull(); | ||
205 | } | ||
206 | public override void Dereference(BSScene physicsScene) { } | ||
207 | } | ||
208 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs new file mode 100644 index 0000000..ba17059 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs | |||
@@ -0,0 +1,175 @@ | |||
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.BulletSNPlugin | ||
42 | { | ||
43 | public sealed class BSTerrainHeightmap : BSTerrainPhys | ||
44 | { | ||
45 | static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]"; | ||
46 | |||
47 | BulletHeightMapInfo 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 BulletHeightMapInfo(id, initialMap, null); | ||
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 BulletHeightMapInfo(id, initialMap, null); | ||
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 | m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, | ||
95 | m_mapInfo.minCoords, m_mapInfo.maxCoords, | ||
96 | m_mapInfo.heightMap, BSParam.TerrainCollisionMargin); | ||
97 | |||
98 | // Create the terrain shape from the mapInfo | ||
99 | m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), | ||
100 | BSPhysicsShapeType.SHAPE_TERRAIN); | ||
101 | |||
102 | // The terrain object initial position is at the center of the object | ||
103 | Vector3 centerPos; | ||
104 | centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f); | ||
105 | centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); | ||
106 | centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f - 0.5f); | ||
107 | |||
108 | m_mapInfo.terrainBody = new BulletBody(m_mapInfo.ID, | ||
109 | BulletSimAPI.CreateBodyWithDefaultMotionState2(m_mapInfo.terrainShape.ptr, | ||
110 | m_mapInfo.ID, centerPos, Quaternion.Identity)); | ||
111 | |||
112 | // Set current terrain attributes | ||
113 | BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainFriction); | ||
114 | BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainHitFraction); | ||
115 | BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, BSParam.TerrainRestitution); | ||
116 | BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
117 | |||
118 | // Return the new terrain to the world of physical objects | ||
119 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr, centerPos, Quaternion.Identity); | ||
120 | |||
121 | // redo its bounding box now that it is in the world | ||
122 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | ||
123 | |||
124 | m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; | ||
125 | m_mapInfo.terrainBody.ApplyCollisionMask(); | ||
126 | |||
127 | // Make it so the terrain will not move or be considered for movement. | ||
128 | BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | ||
129 | |||
130 | return; | ||
131 | } | ||
132 | |||
133 | // If there is information in m_mapInfo pointing to physical structures, release same. | ||
134 | private void ReleaseHeightMapTerrain() | ||
135 | { | ||
136 | if (m_mapInfo != null) | ||
137 | { | ||
138 | if (m_mapInfo.terrainBody.HasPhysicalBody) | ||
139 | { | ||
140 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | ||
141 | // Frees both the body and the shape. | ||
142 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | ||
143 | BulletSimAPI.ReleaseHeightMapInfo2(m_mapInfo.Ptr); | ||
144 | } | ||
145 | } | ||
146 | m_mapInfo = null; | ||
147 | } | ||
148 | |||
149 | // The passed position is relative to the base of the region. | ||
150 | public override float GetTerrainHeightAtXYZ(Vector3 pos) | ||
151 | { | ||
152 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | ||
153 | |||
154 | int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X; | ||
155 | try | ||
156 | { | ||
157 | ret = m_mapInfo.heightMap[mapIndex]; | ||
158 | } | ||
159 | catch | ||
160 | { | ||
161 | // Sometimes they give us wonky values of X and Y. Give a warning and return something. | ||
162 | PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", | ||
163 | LogHeader, m_mapInfo.terrainRegionBase, pos); | ||
164 | ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | ||
165 | } | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | // The passed position is relative to the base of the region. | ||
170 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
171 | { | ||
172 | return PhysicsScene.SimpleWaterLevel; | ||
173 | } | ||
174 | } | ||
175 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs new file mode 100644 index 0000000..66d62f0 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs | |||
@@ -0,0 +1,461 @@ | |||
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.BulletSNPlugin | ||
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 | public BSScene 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 | 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 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) | ||
115 | { | ||
116 | PhysicsScene = physicsScene; | ||
117 | m_terrains = new Dictionary<Vector3,BSTerrainPhys>(); | ||
118 | |||
119 | // Assume one region of default size | ||
120 | m_worldOffset = Vector3.Zero; | ||
121 | m_worldMax = new Vector3(DefaultRegionSize); | ||
122 | MegaRegionParentPhysicsScene = null; | ||
123 | } | ||
124 | |||
125 | public void Dispose() | ||
126 | { | ||
127 | ReleaseGroundPlaneAndTerrain(); | ||
128 | } | ||
129 | |||
130 | // Create the initial instance of terrain and the underlying ground plane. | ||
131 | // This is called from the initialization routine so we presume it is | ||
132 | // safe to call Bullet in real time. We hope no one is moving prims around yet. | ||
133 | public void CreateInitialGroundPlaneAndTerrain() | ||
134 | { | ||
135 | // The ground plane is here to catch things that are trying to drop to negative infinity | ||
136 | BulletShape groundPlaneShape = new BulletShape( | ||
137 | BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, | ||
138 | BSParam.TerrainCollisionMargin), | ||
139 | BSPhysicsShapeType.SHAPE_GROUNDPLANE); | ||
140 | m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, | ||
141 | BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, | ||
142 | Vector3.Zero, Quaternion.Identity)); | ||
143 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr, Vector3.Zero, Quaternion.Identity); | ||
144 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr); | ||
145 | // Ground plane does not move | ||
146 | BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); | ||
147 | // Everything collides with the ground plane. | ||
148 | m_groundPlane.collisionType = CollisionType.Groundplane; | ||
149 | m_groundPlane.ApplyCollisionMask(); | ||
150 | |||
151 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. | ||
152 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); | ||
153 | m_terrains.Add(Vector3.Zero, initialTerrain); | ||
154 | } | ||
155 | |||
156 | // Release all the terrain structures we might have allocated | ||
157 | public void ReleaseGroundPlaneAndTerrain() | ||
158 | { | ||
159 | if (m_groundPlane.HasPhysicalBody) | ||
160 | { | ||
161 | if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) | ||
162 | { | ||
163 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); | ||
164 | } | ||
165 | m_groundPlane.Clear(); | ||
166 | } | ||
167 | |||
168 | ReleaseTerrain(); | ||
169 | } | ||
170 | |||
171 | // Release all the terrain we have allocated | ||
172 | public void ReleaseTerrain() | ||
173 | { | ||
174 | lock (m_terrains) | ||
175 | { | ||
176 | foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) | ||
177 | { | ||
178 | kvp.Value.Dispose(); | ||
179 | } | ||
180 | m_terrains.Clear(); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | // The simulator wants to set a new heightmap for the terrain. | ||
185 | public void SetTerrain(float[] heightMap) { | ||
186 | float[] localHeightMap = heightMap; | ||
187 | // If there are multiple requests for changes to the same terrain between ticks, | ||
188 | // only do that last one. | ||
189 | PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() | ||
190 | { | ||
191 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) | ||
192 | { | ||
193 | // If a child of a mega-region, we shouldn't have any terrain allocated for us | ||
194 | ReleaseGroundPlaneAndTerrain(); | ||
195 | // If doing the mega-prim stuff and we are the child of the zero region, | ||
196 | // the terrain is added to our parent | ||
197 | if (MegaRegionParentPhysicsScene is BSScene) | ||
198 | { | ||
199 | DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", | ||
200 | BSScene.DetailLogZero, m_worldOffset, m_worldMax); | ||
201 | ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( | ||
202 | BSScene.CHILDTERRAIN_ID, localHeightMap, | ||
203 | m_worldOffset, m_worldOffset + DefaultRegionSize, true); | ||
204 | } | ||
205 | } | ||
206 | else | ||
207 | { | ||
208 | // If not doing the mega-prim thing, just change the terrain | ||
209 | DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); | ||
210 | |||
211 | UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, | ||
212 | m_worldOffset, m_worldOffset + DefaultRegionSize, true); | ||
213 | } | ||
214 | }); | ||
215 | } | ||
216 | |||
217 | // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain | ||
218 | // based on the passed information. The 'id' should be either the terrain id or | ||
219 | // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. | ||
220 | // The latter feature is for creating child terrains for mega-regions. | ||
221 | // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new | ||
222 | // terrain shape is created and added to the body. | ||
223 | // This call is most often used to update the heightMap and parameters of the terrain. | ||
224 | // (The above does suggest that some simplification/refactoring is in order.) | ||
225 | // Called during taint-time. | ||
226 | private void UpdateTerrain(uint id, float[] heightMap, | ||
227 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) | ||
228 | { | ||
229 | DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}", | ||
230 | BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); | ||
231 | |||
232 | // Find high and low points of passed heightmap. | ||
233 | // The min and max passed in is usually the area objects can be in (maximum | ||
234 | // object height, for instance). The terrain wants the bounding box for the | ||
235 | // terrain so replace passed min and max Z with the actual terrain min/max Z. | ||
236 | float minZ = float.MaxValue; | ||
237 | float maxZ = float.MinValue; | ||
238 | foreach (float height in heightMap) | ||
239 | { | ||
240 | if (height < minZ) minZ = height; | ||
241 | if (height > maxZ) maxZ = height; | ||
242 | } | ||
243 | if (minZ == maxZ) | ||
244 | { | ||
245 | // If min and max are the same, reduce min a little bit so a good bounding box is created. | ||
246 | minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE; | ||
247 | } | ||
248 | minCoords.Z = minZ; | ||
249 | maxCoords.Z = maxZ; | ||
250 | |||
251 | Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); | ||
252 | |||
253 | lock (m_terrains) | ||
254 | { | ||
255 | BSTerrainPhys terrainPhys; | ||
256 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) | ||
257 | { | ||
258 | // There is already a terrain in this spot. Free the old and build the new. | ||
259 | DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", | ||
260 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); | ||
261 | |||
262 | // Remove old terrain from the collection | ||
263 | m_terrains.Remove(terrainRegionBase); | ||
264 | // Release any physical memory it may be using. | ||
265 | terrainPhys.Dispose(); | ||
266 | |||
267 | if (MegaRegionParentPhysicsScene == null) | ||
268 | { | ||
269 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | ||
270 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | ||
271 | |||
272 | m_terrainModified = true; | ||
273 | } | ||
274 | else | ||
275 | { | ||
276 | // It's possible that Combine() was called after this code was queued. | ||
277 | // If we are a child of combined regions, we don't create any terrain for us. | ||
278 | DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero); | ||
279 | |||
280 | // Get rid of any terrain that may have been allocated for us. | ||
281 | ReleaseGroundPlaneAndTerrain(); | ||
282 | |||
283 | // I hate doing this, but just bail | ||
284 | return; | ||
285 | } | ||
286 | } | ||
287 | else | ||
288 | { | ||
289 | // We don't know about this terrain so either we are creating a new terrain or | ||
290 | // our mega-prim child is giving us a new terrain to add to the phys world | ||
291 | |||
292 | // if this is a child terrain, calculate a unique terrain id | ||
293 | uint newTerrainID = id; | ||
294 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) | ||
295 | newTerrainID = ++m_terrainCount; | ||
296 | |||
297 | DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", | ||
298 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); | ||
299 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | ||
300 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | ||
301 | |||
302 | m_terrainModified = true; | ||
303 | } | ||
304 | } | ||
305 | } | ||
306 | |||
307 | // TODO: redo terrain implementation selection to allow other base types than heightMap. | ||
308 | private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) | ||
309 | { | ||
310 | PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", | ||
311 | LogHeader, PhysicsScene.RegionName, terrainRegionBase, | ||
312 | (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); | ||
313 | BSTerrainPhys newTerrainPhys = null; | ||
314 | switch ((int)BSParam.TerrainImplementation) | ||
315 | { | ||
316 | case (int)BSTerrainPhys.TerrainImplementation.Heightmap: | ||
317 | newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, | ||
318 | heightMap, minCoords, maxCoords); | ||
319 | break; | ||
320 | case (int)BSTerrainPhys.TerrainImplementation.Mesh: | ||
321 | newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, | ||
322 | heightMap, minCoords, maxCoords); | ||
323 | break; | ||
324 | default: | ||
325 | PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", | ||
326 | LogHeader, | ||
327 | (int)BSParam.TerrainImplementation, | ||
328 | BSParam.TerrainImplementation, | ||
329 | PhysicsScene.RegionName, terrainRegionBase); | ||
330 | break; | ||
331 | } | ||
332 | return newTerrainPhys; | ||
333 | } | ||
334 | |||
335 | // Return 'true' of this position is somewhere in known physical terrain space | ||
336 | public bool IsWithinKnownTerrain(Vector3 pos) | ||
337 | { | ||
338 | Vector3 terrainBaseXYZ; | ||
339 | BSTerrainPhys physTerrain; | ||
340 | return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); | ||
341 | } | ||
342 | |||
343 | // Given an X and Y, find the height of the terrain. | ||
344 | // Since we could be handling multiple terrains for a mega-region, | ||
345 | // the base of the region is calcuated assuming all regions are | ||
346 | // the same size and that is the default. | ||
347 | // Once the heightMapInfo is found, we have all the information to | ||
348 | // compute the offset into the array. | ||
349 | private float lastHeightTX = 999999f; | ||
350 | private float lastHeightTY = 999999f; | ||
351 | private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; | ||
352 | public float GetTerrainHeightAtXYZ(Vector3 pos) | ||
353 | { | ||
354 | float tX = pos.X; | ||
355 | float tY = pos.Y; | ||
356 | // You'd be surprized at the number of times this routine is called | ||
357 | // with the same parameters as last time. | ||
358 | if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY)) | ||
359 | return lastHeight; | ||
360 | m_terrainModified = false; | ||
361 | |||
362 | lastHeightTX = tX; | ||
363 | lastHeightTY = tY; | ||
364 | float ret = HEIGHT_GETHEIGHT_RET; | ||
365 | |||
366 | Vector3 terrainBaseXYZ; | ||
367 | BSTerrainPhys physTerrain; | ||
368 | if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) | ||
369 | { | ||
370 | ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ); | ||
371 | } | ||
372 | else | ||
373 | { | ||
374 | PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", | ||
375 | LogHeader, PhysicsScene.RegionName, tX, tY); | ||
376 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", | ||
377 | BSScene.DetailLogZero, pos, terrainBaseXYZ); | ||
378 | } | ||
379 | |||
380 | lastHeight = ret; | ||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | public float GetWaterLevelAtXYZ(Vector3 pos) | ||
385 | { | ||
386 | float ret = WATER_HEIGHT_GETHEIGHT_RET; | ||
387 | |||
388 | Vector3 terrainBaseXYZ; | ||
389 | BSTerrainPhys physTerrain; | ||
390 | if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) | ||
391 | { | ||
392 | ret = physTerrain.GetWaterLevelAtXYZ(pos); | ||
393 | } | ||
394 | else | ||
395 | { | ||
396 | PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", | ||
397 | LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); | ||
398 | } | ||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | // Given an address, return 'true' of there is a description of that terrain and output | ||
403 | // the descriptor class and the 'base' fo the addresses therein. | ||
404 | private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) | ||
405 | { | ||
406 | int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | ||
407 | int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
408 | Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | ||
409 | |||
410 | BSTerrainPhys physTerrain = null; | ||
411 | lock (m_terrains) | ||
412 | { | ||
413 | m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); | ||
414 | } | ||
415 | outTerrainBase = terrainBaseXYZ; | ||
416 | outPhysTerrain = physTerrain; | ||
417 | return (physTerrain != null); | ||
418 | } | ||
419 | |||
420 | // Although no one seems to check this, I do support combining. | ||
421 | public bool SupportsCombining() | ||
422 | { | ||
423 | return true; | ||
424 | } | ||
425 | |||
426 | // This routine is called two ways: | ||
427 | // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum | ||
428 | // extent of the combined regions. This is to inform the parent of the size | ||
429 | // of the combined regions. | ||
430 | // and one with 'offset' as the offset of the child region to the base region, | ||
431 | // 'pScene' pointing to the parent and 'extents' of zero. This informs the | ||
432 | // child of its relative base and new parent. | ||
433 | public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) | ||
434 | { | ||
435 | m_worldOffset = offset; | ||
436 | m_worldMax = extents; | ||
437 | MegaRegionParentPhysicsScene = pScene; | ||
438 | if (pScene != null) | ||
439 | { | ||
440 | // We are a child. | ||
441 | // We want m_worldMax to be the highest coordinate of our piece of terrain. | ||
442 | m_worldMax = offset + DefaultRegionSize; | ||
443 | } | ||
444 | DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}", | ||
445 | BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax); | ||
446 | } | ||
447 | |||
448 | // Unhook all the combining that I know about. | ||
449 | public void UnCombine(PhysicsScene pScene) | ||
450 | { | ||
451 | // Just like ODE, we don't do anything yet. | ||
452 | DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero); | ||
453 | } | ||
454 | |||
455 | |||
456 | private void DetailLog(string msg, params Object[] args) | ||
457 | { | ||
458 | PhysicsScene.PhysicsLogging.Write(msg, args); | ||
459 | } | ||
460 | } | ||
461 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs new file mode 100644 index 0000000..6083dd4 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs | |||
@@ -0,0 +1,267 @@ | |||
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.BulletSNPlugin | ||
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 | if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap, | ||
80 | m_sizeX, m_sizeY, | ||
81 | (float)m_sizeX, (float)m_sizeY, | ||
82 | Vector3.Zero, 1.0f, | ||
83 | out indicesCount, out indices, out verticesCount, out vertices)) | ||
84 | { | ||
85 | // DISASTER!! | ||
86 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID); | ||
87 | PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); | ||
88 | // Something is very messed up and a crash is in our future. | ||
89 | return; | ||
90 | } | ||
91 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", | ||
92 | ID, indicesCount, indices.Length, verticesCount, vertices.Length); | ||
93 | |||
94 | m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | ||
95 | indicesCount, indices, verticesCount, vertices), | ||
96 | BSPhysicsShapeType.SHAPE_MESH); | ||
97 | if (!m_terrainShape.HasPhysicalShape) | ||
98 | { | ||
99 | // DISASTER!! | ||
100 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); | ||
101 | physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); | ||
102 | // Something is very messed up and a crash is in our future. | ||
103 | return; | ||
104 | } | ||
105 | |||
106 | Vector3 pos = regionBase; | ||
107 | Quaternion rot = Quaternion.Identity; | ||
108 | |||
109 | m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); | ||
110 | if (!m_terrainBody.HasPhysicalBody) | ||
111 | { | ||
112 | // DISASTER!! | ||
113 | physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); | ||
114 | // Something is very messed up and a crash is in our future. | ||
115 | return; | ||
116 | } | ||
117 | |||
118 | // Set current terrain attributes | ||
119 | BulletSimAPI.SetFriction2(m_terrainBody.ptr, BSParam.TerrainFriction); | ||
120 | BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, BSParam.TerrainHitFraction); | ||
121 | BulletSimAPI.SetRestitution2(m_terrainBody.ptr, BSParam.TerrainRestitution); | ||
122 | BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
123 | |||
124 | // Static objects are not very massive. | ||
125 | BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); | ||
126 | |||
127 | // Put the new terrain to the world of physical objects | ||
128 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr, pos, rot); | ||
129 | |||
130 | // Redo its bounding box now that it is in the world | ||
131 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); | ||
132 | |||
133 | m_terrainBody.collisionType = CollisionType.Terrain; | ||
134 | m_terrainBody.ApplyCollisionMask(); | ||
135 | |||
136 | // Make it so the terrain will not move or be considered for movement. | ||
137 | BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | ||
138 | } | ||
139 | |||
140 | public override void Dispose() | ||
141 | { | ||
142 | if (m_terrainBody.HasPhysicalBody) | ||
143 | { | ||
144 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); | ||
145 | // Frees both the body and the shape. | ||
146 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | public override float GetTerrainHeightAtXYZ(Vector3 pos) | ||
151 | { | ||
152 | // For the moment use the saved heightmap to get the terrain height. | ||
153 | // TODO: raycast downward to find the true terrain below the position. | ||
154 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | ||
155 | |||
156 | int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X; | ||
157 | try | ||
158 | { | ||
159 | ret = m_savedHeightMap[mapIndex]; | ||
160 | } | ||
161 | catch | ||
162 | { | ||
163 | // Sometimes they give us wonky values of X and Y. Give a warning and return something. | ||
164 | PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", | ||
165 | LogHeader, TerrainBase, pos); | ||
166 | ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | ||
167 | } | ||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | // The passed position is relative to the base of the region. | ||
172 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
173 | { | ||
174 | return PhysicsScene.SimpleWaterLevel; | ||
175 | } | ||
176 | |||
177 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). | ||
178 | // Return 'true' if successfully created. | ||
179 | public static bool ConvertHeightmapToMesh( | ||
180 | BSScene physicsScene, | ||
181 | float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap | ||
182 | float extentX, float extentY, // zero based range for output vertices | ||
183 | Vector3 extentBase, // base to be added to all vertices | ||
184 | float magnification, // number of vertices to create between heightMap coords | ||
185 | out int indicesCountO, out int[] indicesO, | ||
186 | out int verticesCountO, out float[] verticesO) | ||
187 | { | ||
188 | bool ret = false; | ||
189 | |||
190 | int indicesCount = 0; | ||
191 | int verticesCount = 0; | ||
192 | int[] indices = new int[0]; | ||
193 | float[] vertices = new float[0]; | ||
194 | |||
195 | // Simple mesh creation which assumes magnification == 1. | ||
196 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. | ||
197 | |||
198 | // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop | ||
199 | // from zero to <= sizeX). The triangle indices are then generated as two triangles | ||
200 | // per heightmap point. There are sizeX by sizeY of these squares. The extra row and | ||
201 | // column of vertices are used to complete the triangles of the last row and column | ||
202 | // of the heightmap. | ||
203 | try | ||
204 | { | ||
205 | // One vertice per heightmap value plus the vertices off the top and bottom edge. | ||
206 | int totalVertices = (sizeX + 1) * (sizeY + 1); | ||
207 | vertices = new float[totalVertices * 3]; | ||
208 | int totalIndices = sizeX * sizeY * 6; | ||
209 | indices = new int[totalIndices]; | ||
210 | |||
211 | float magX = (float)sizeX / extentX; | ||
212 | float magY = (float)sizeY / extentY; | ||
213 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", | ||
214 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); | ||
215 | float minHeight = float.MaxValue; | ||
216 | // Note that sizeX+1 vertices are created since there is land between this and the next region. | ||
217 | for (int yy = 0; yy <= sizeY; yy++) | ||
218 | { | ||
219 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times | ||
220 | { | ||
221 | int offset = yy * sizeX + xx; | ||
222 | // Extend the height with the height from the last row or column | ||
223 | if (yy == sizeY) offset -= sizeX; | ||
224 | if (xx == sizeX) offset -= 1; | ||
225 | float height = heightMap[offset]; | ||
226 | minHeight = Math.Min(minHeight, height); | ||
227 | vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; | ||
228 | vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; | ||
229 | vertices[verticesCount + 2] = height + extentBase.Z; | ||
230 | verticesCount += 3; | ||
231 | } | ||
232 | } | ||
233 | verticesCount = verticesCount / 3; | ||
234 | |||
235 | for (int yy = 0; yy < sizeY; yy++) | ||
236 | { | ||
237 | for (int xx = 0; xx < sizeX; xx++) | ||
238 | { | ||
239 | int offset = yy * (sizeX + 1) + xx; | ||
240 | // Each vertices is presumed to be the upper left corner of a box of two triangles | ||
241 | indices[indicesCount + 0] = offset; | ||
242 | indices[indicesCount + 1] = offset + 1; | ||
243 | indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column | ||
244 | indices[indicesCount + 3] = offset + 1; | ||
245 | indices[indicesCount + 4] = offset + sizeX + 2; | ||
246 | indices[indicesCount + 5] = offset + sizeX + 1; | ||
247 | indicesCount += 6; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | ret = true; | ||
252 | } | ||
253 | catch (Exception e) | ||
254 | { | ||
255 | physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", | ||
256 | LogHeader, physicsScene.RegionName, extentBase, e); | ||
257 | } | ||
258 | |||
259 | indicesCountO = indicesCount; | ||
260 | indicesO = indices; | ||
261 | verticesCountO = verticesCount; | ||
262 | verticesO = vertices; | ||
263 | |||
264 | return ret; | ||
265 | } | ||
266 | } | ||
267 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs new file mode 100644 index 0000000..93643c9 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs | |||
@@ -0,0 +1,1603 @@ | |||
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.Security; | ||
32 | using System.Text; | ||
33 | using BulletXNA; | ||
34 | using OpenMetaverse; | ||
35 | using BulletXNA.LinearMath; | ||
36 | using BulletXNA.BulletCollision; | ||
37 | using BulletXNA.BulletDynamics; | ||
38 | using BulletXNA.BulletCollision.CollisionDispatch; | ||
39 | using OpenSim.Framework; | ||
40 | |||
41 | namespace OpenSim.Region.Physics.BulletSNPlugin { | ||
42 | |||
43 | // Classes to allow some type checking for the API | ||
44 | // These hold pointers to allocated objects in the unmanaged space. | ||
45 | |||
46 | |||
47 | |||
48 | // Constraint type values as defined by Bullet | ||
49 | public enum ConstraintType : int | ||
50 | { | ||
51 | POINT2POINT_CONSTRAINT_TYPE = 3, | ||
52 | HINGE_CONSTRAINT_TYPE, | ||
53 | CONETWIST_CONSTRAINT_TYPE, | ||
54 | D6_CONSTRAINT_TYPE, | ||
55 | SLIDER_CONSTRAINT_TYPE, | ||
56 | CONTACT_CONSTRAINT_TYPE, | ||
57 | D6_SPRING_CONSTRAINT_TYPE, | ||
58 | MAX_CONSTRAINT_TYPE | ||
59 | } | ||
60 | |||
61 | // =============================================================================== | ||
62 | [StructLayout(LayoutKind.Sequential)] | ||
63 | public struct ConvexHull | ||
64 | { | ||
65 | Vector3 Offset; | ||
66 | int VertexCount; | ||
67 | Vector3[] Vertices; | ||
68 | } | ||
69 | public enum BSPhysicsShapeType | ||
70 | { | ||
71 | SHAPE_UNKNOWN = 0, | ||
72 | SHAPE_CAPSULE = 1, | ||
73 | SHAPE_BOX = 2, | ||
74 | SHAPE_CONE = 3, | ||
75 | SHAPE_CYLINDER = 4, | ||
76 | SHAPE_SPHERE = 5, | ||
77 | SHAPE_MESH = 6, | ||
78 | SHAPE_HULL = 7, | ||
79 | // following defined by BulletSim | ||
80 | SHAPE_GROUNDPLANE = 20, | ||
81 | SHAPE_TERRAIN = 21, | ||
82 | SHAPE_COMPOUND = 22, | ||
83 | SHAPE_HEIGHTMAP = 23, | ||
84 | }; | ||
85 | |||
86 | // The native shapes have predefined shape hash keys | ||
87 | public enum FixedShapeKey : ulong | ||
88 | { | ||
89 | KEY_NONE = 0, | ||
90 | KEY_BOX = 1, | ||
91 | KEY_SPHERE = 2, | ||
92 | KEY_CONE = 3, | ||
93 | KEY_CYLINDER = 4, | ||
94 | KEY_CAPSULE = 5, | ||
95 | } | ||
96 | |||
97 | [StructLayout(LayoutKind.Sequential)] | ||
98 | public struct ShapeData | ||
99 | { | ||
100 | public uint ID; | ||
101 | public BSPhysicsShapeType Type; | ||
102 | public Vector3 Position; | ||
103 | public Quaternion Rotation; | ||
104 | public Vector3 Velocity; | ||
105 | public Vector3 Scale; | ||
106 | public float Mass; | ||
107 | public float Buoyancy; | ||
108 | public System.UInt64 HullKey; | ||
109 | public System.UInt64 MeshKey; | ||
110 | public float Friction; | ||
111 | public float Restitution; | ||
112 | public float Collidable; // true of things bump into this | ||
113 | public float Static; // true if a static object. Otherwise gravity, etc. | ||
114 | public float Solid; // true if object cannot be passed through | ||
115 | public Vector3 Size; | ||
116 | |||
117 | // note that bools are passed as floats since bool size changes by language and architecture | ||
118 | public const float numericTrue = 1f; | ||
119 | public const float numericFalse = 0f; | ||
120 | } | ||
121 | [StructLayout(LayoutKind.Sequential)] | ||
122 | public struct SweepHit | ||
123 | { | ||
124 | public uint ID; | ||
125 | public float Fraction; | ||
126 | public Vector3 Normal; | ||
127 | public Vector3 Point; | ||
128 | } | ||
129 | [StructLayout(LayoutKind.Sequential)] | ||
130 | public struct RaycastHit | ||
131 | { | ||
132 | public uint ID; | ||
133 | public float Fraction; | ||
134 | public Vector3 Normal; | ||
135 | } | ||
136 | [StructLayout(LayoutKind.Sequential)] | ||
137 | public struct CollisionDesc | ||
138 | { | ||
139 | public uint aID; | ||
140 | public uint bID; | ||
141 | public Vector3 point; | ||
142 | public Vector3 normal; | ||
143 | } | ||
144 | [StructLayout(LayoutKind.Sequential)] | ||
145 | public struct EntityProperties | ||
146 | { | ||
147 | public uint ID; | ||
148 | public Vector3 Position; | ||
149 | public Quaternion Rotation; | ||
150 | public Vector3 Velocity; | ||
151 | public Vector3 Acceleration; | ||
152 | public Vector3 RotationalVelocity; | ||
153 | public override string ToString() | ||
154 | { | ||
155 | return string.Format("ID:{0}, Pos:<{1:F},{2:F},{3:F}>, Rot:<{4:F},{5:F},{6:F},{7:F}>, LVel:<{8:F},{9:F},{10:F}>, AVel:<{11:F},{12:F},{13:F}>", | ||
156 | ID.ToString(), | ||
157 | Position.X,Position.Y,Position.Z, | ||
158 | Rotation.X,Rotation.Y,Rotation.Z,Rotation.W, | ||
159 | Velocity.X,Velocity.Y,Velocity.Z, | ||
160 | RotationalVelocity.X,RotationalVelocity.Y,RotationalVelocity.Z | ||
161 | ); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | // Format of this structure must match the definition in the C++ code | ||
166 | // NOTE: adding the X causes compile breaks if used. These are unused symbols | ||
167 | // that can be removed from both here and the unmanaged definition of this structure. | ||
168 | [StructLayout(LayoutKind.Sequential)] | ||
169 | public struct ConfigurationParameters | ||
170 | { | ||
171 | public float defaultFriction; | ||
172 | public float defaultDensity; | ||
173 | public float defaultRestitution; | ||
174 | public float collisionMargin; | ||
175 | public float gravity; | ||
176 | |||
177 | public float XlinearDamping; | ||
178 | public float XangularDamping; | ||
179 | public float XdeactivationTime; | ||
180 | public float XlinearSleepingThreshold; | ||
181 | public float XangularSleepingThreshold; | ||
182 | public float XccdMotionThreshold; | ||
183 | public float XccdSweptSphereRadius; | ||
184 | public float XcontactProcessingThreshold; | ||
185 | |||
186 | public float XterrainImplementation; | ||
187 | public float XterrainFriction; | ||
188 | public float XterrainHitFraction; | ||
189 | public float XterrainRestitution; | ||
190 | public float XterrainCollisionMargin; | ||
191 | |||
192 | public float XavatarFriction; | ||
193 | public float XavatarStandingFriction; | ||
194 | public float XavatarDensity; | ||
195 | public float XavatarRestitution; | ||
196 | public float XavatarCapsuleWidth; | ||
197 | public float XavatarCapsuleDepth; | ||
198 | public float XavatarCapsuleHeight; | ||
199 | public float XavatarContactProcessingThreshold; | ||
200 | |||
201 | public float XvehicleAngularDamping; | ||
202 | |||
203 | public float maxPersistantManifoldPoolSize; | ||
204 | public float maxCollisionAlgorithmPoolSize; | ||
205 | public float shouldDisableContactPoolDynamicAllocation; | ||
206 | public float shouldForceUpdateAllAabbs; | ||
207 | public float shouldRandomizeSolverOrder; | ||
208 | public float shouldSplitSimulationIslands; | ||
209 | public float shouldEnableFrictionCaching; | ||
210 | public float numberOfSolverIterations; | ||
211 | |||
212 | public float XlinksetImplementation; | ||
213 | public float XlinkConstraintUseFrameOffset; | ||
214 | public float XlinkConstraintEnableTransMotor; | ||
215 | public float XlinkConstraintTransMotorMaxVel; | ||
216 | public float XlinkConstraintTransMotorMaxForce; | ||
217 | public float XlinkConstraintERP; | ||
218 | public float XlinkConstraintCFM; | ||
219 | public float XlinkConstraintSolverIterations; | ||
220 | |||
221 | public float physicsLoggingFrames; | ||
222 | |||
223 | public const float numericTrue = 1f; | ||
224 | public const float numericFalse = 0f; | ||
225 | } | ||
226 | |||
227 | |||
228 | // The states a bullet collision object can have | ||
229 | |||
230 | public enum ActivationState : uint | ||
231 | { | ||
232 | UNDEFINED = 0, | ||
233 | ACTIVE_TAG = 1, | ||
234 | ISLAND_SLEEPING = 2, | ||
235 | WANTS_DEACTIVATION = 3, | ||
236 | DISABLE_DEACTIVATION = 4, | ||
237 | DISABLE_SIMULATION = 5, | ||
238 | } | ||
239 | |||
240 | public enum CollisionObjectTypes : int | ||
241 | { | ||
242 | CO_COLLISION_OBJECT = 1 << 0, | ||
243 | CO_RIGID_BODY = 1 << 1, | ||
244 | CO_GHOST_OBJECT = 1 << 2, | ||
245 | CO_SOFT_BODY = 1 << 3, | ||
246 | CO_HF_FLUID = 1 << 4, | ||
247 | CO_USER_TYPE = 1 << 5, | ||
248 | } | ||
249 | |||
250 | // Values used by Bullet and BulletSim to control object properties. | ||
251 | // Bullet's "CollisionFlags" has more to do with operations on the | ||
252 | // object (if collisions happen, if gravity effects it, ...). | ||
253 | [Flags] | ||
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, | ||
265 | BS_FLOATS_ON_WATER = 1 << 11, | ||
266 | BS_VEHICLE_COLLISIONS = 1 << 12, | ||
267 | BS_NONE = 0, | ||
268 | BS_ALL = 0xFFFFFFFF, | ||
269 | |||
270 | // These are the collision flags switched depending on physical state. | ||
271 | // The other flags are used for other things and should not be fooled with. | ||
272 | BS_ACTIVE = CF_STATIC_OBJECT | ||
273 | | CF_KINEMATIC_OBJECT | ||
274 | | CF_NO_CONTACT_RESPONSE | ||
275 | }; | ||
276 | |||
277 | // Values for collisions groups and masks | ||
278 | public enum CollisionFilterGroups : uint | ||
279 | { | ||
280 | // Don't use the bit definitions!! Define the use in a | ||
281 | // filter/mask definition below. This way collision interactions | ||
282 | // are more easily debugged. | ||
283 | BNoneGroup = 0, | ||
284 | BDefaultGroup = 1 << 0, | ||
285 | BStaticGroup = 1 << 1, | ||
286 | BKinematicGroup = 1 << 2, | ||
287 | BDebrisGroup = 1 << 3, | ||
288 | BSensorTrigger = 1 << 4, | ||
289 | BCharacterGroup = 1 << 5, | ||
290 | BAllGroup = 0xFFFFFFFF, | ||
291 | // Filter groups defined by BulletSim | ||
292 | BGroundPlaneGroup = 1 << 10, | ||
293 | BTerrainGroup = 1 << 11, | ||
294 | BRaycastGroup = 1 << 12, | ||
295 | BSolidGroup = 1 << 13, | ||
296 | // BLinksetGroup = xx // a linkset proper is either static or dynamic | ||
297 | BLinksetChildGroup = 1 << 14, | ||
298 | // The collsion filters and masked are defined in one place -- don't want them scattered | ||
299 | AvatarGroup = BCharacterGroup, | ||
300 | AvatarMask = BAllGroup, | ||
301 | ObjectGroup = BSolidGroup, | ||
302 | ObjectMask = BAllGroup, | ||
303 | StaticObjectGroup = BStaticGroup, | ||
304 | StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much | ||
305 | LinksetGroup = BLinksetChildGroup, | ||
306 | LinksetMask = BAllGroup & ~BLinksetChildGroup, // linkset objects don't collide with each other | ||
307 | VolumeDetectGroup = BSensorTrigger, | ||
308 | VolumeDetectMask = ~BSensorTrigger, | ||
309 | TerrainGroup = BTerrainGroup, | ||
310 | TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide | ||
311 | GroundPlaneGroup = BGroundPlaneGroup, | ||
312 | GroundPlaneMask = BAllGroup | ||
313 | |||
314 | }; | ||
315 | |||
316 | // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 | ||
317 | // ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. | ||
318 | public enum ConstraintParams : int | ||
319 | { | ||
320 | BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730 | ||
321 | BT_CONSTRAINT_STOP_ERP, | ||
322 | BT_CONSTRAINT_CFM, | ||
323 | BT_CONSTRAINT_STOP_CFM, | ||
324 | }; | ||
325 | public enum ConstraintParamAxis : int | ||
326 | { | ||
327 | AXIS_LINEAR_X = 0, | ||
328 | AXIS_LINEAR_Y, | ||
329 | AXIS_LINEAR_Z, | ||
330 | AXIS_ANGULAR_X, | ||
331 | AXIS_ANGULAR_Y, | ||
332 | AXIS_ANGULAR_Z, | ||
333 | AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls | ||
334 | AXIS_ANGULAR_ALL, | ||
335 | AXIS_ALL | ||
336 | }; | ||
337 | |||
338 | // =============================================================================== | ||
339 | static class BulletSimAPI { | ||
340 | private static int m_collisionsThisFrame; | ||
341 | public delegate void DebugLogCallback(string msg); | ||
342 | /// <summary> | ||
343 | /// | ||
344 | /// </summary> | ||
345 | /// <param name="p"></param> | ||
346 | /// <param name="p_2"></param> | ||
347 | internal static bool RemoveObjectFromWorld2(object pWorld, object pBody) | ||
348 | { | ||
349 | DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; | ||
350 | RigidBody body = pBody as RigidBody; | ||
351 | world.RemoveRigidBody(body); | ||
352 | return true; | ||
353 | } | ||
354 | |||
355 | internal static void SetRestitution2(object pBody, float pRestitution) | ||
356 | { | ||
357 | RigidBody body = pBody as RigidBody; | ||
358 | body.SetRestitution(pRestitution); | ||
359 | } | ||
360 | |||
361 | internal static void SetMargin2(object pShape, float pMargin) | ||
362 | { | ||
363 | CollisionShape shape = pShape as CollisionShape; | ||
364 | shape.SetMargin(pMargin); | ||
365 | } | ||
366 | |||
367 | internal static void SetLocalScaling2(object pShape, Vector3 pScale) | ||
368 | { | ||
369 | CollisionShape shape = pShape as CollisionShape; | ||
370 | IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); | ||
371 | shape.SetLocalScaling(ref vec); | ||
372 | |||
373 | } | ||
374 | |||
375 | internal static void SetContactProcessingThreshold2(object pBody, float contactprocessingthreshold) | ||
376 | { | ||
377 | RigidBody body = pBody as RigidBody; | ||
378 | body.SetContactProcessingThreshold(contactprocessingthreshold); | ||
379 | } | ||
380 | |||
381 | internal static void SetCcdMotionThreshold2(object pBody, float pccdMotionThreashold) | ||
382 | { | ||
383 | RigidBody body = pBody as RigidBody; | ||
384 | body.SetCcdMotionThreshold(pccdMotionThreashold); | ||
385 | } | ||
386 | |||
387 | internal static void SetCcdSweptSphereRadius2(object pBody, float pCcdSweptSphereRadius) | ||
388 | { | ||
389 | RigidBody body = pBody as RigidBody; | ||
390 | body.SetCcdSweptSphereRadius(pCcdSweptSphereRadius); | ||
391 | } | ||
392 | |||
393 | internal static void SetAngularFactorV2(object pBody, Vector3 pAngularFactor) | ||
394 | { | ||
395 | RigidBody body = pBody as RigidBody; | ||
396 | body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z)); | ||
397 | } | ||
398 | |||
399 | internal static CollisionFlags AddToCollisionFlags2(object pBody, CollisionFlags pcollisionFlags) | ||
400 | { | ||
401 | CollisionObject body = pBody as CollisionObject; | ||
402 | CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags(); | ||
403 | existingcollisionFlags |= pcollisionFlags; | ||
404 | body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); | ||
405 | return (CollisionFlags) (uint) existingcollisionFlags; | ||
406 | } | ||
407 | |||
408 | internal static void AddObjectToWorld2(object pWorld, object pBody) | ||
409 | { | ||
410 | RigidBody body = pBody as RigidBody; | ||
411 | DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; | ||
412 | //if (!(body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE && body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE)) | ||
413 | |||
414 | world.AddRigidBody(body); | ||
415 | |||
416 | //if (body.GetBroadphaseHandle() != null) | ||
417 | // world.UpdateSingleAabb(body); | ||
418 | } | ||
419 | |||
420 | internal static void AddObjectToWorld2(object pWorld, object pBody, Vector3 _position, Quaternion _orientation) | ||
421 | { | ||
422 | RigidBody body = pBody as RigidBody; | ||
423 | DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; | ||
424 | //if (!(body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE && body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE)) | ||
425 | |||
426 | world.AddRigidBody(body); | ||
427 | IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z); | ||
428 | IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z, | ||
429 | _orientation.W); | ||
430 | IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); | ||
431 | mat._origin = vposition; | ||
432 | body.SetWorldTransform(mat); | ||
433 | //if (body.GetBroadphaseHandle() != null) | ||
434 | // world.UpdateSingleAabb(body); | ||
435 | } | ||
436 | |||
437 | internal static void ForceActivationState2(object pBody, ActivationState pActivationState) | ||
438 | { | ||
439 | CollisionObject body = pBody as CollisionObject; | ||
440 | body.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState); | ||
441 | } | ||
442 | |||
443 | internal static void UpdateSingleAabb2(object pWorld, object pBody) | ||
444 | { | ||
445 | CollisionObject body = pBody as CollisionObject; | ||
446 | DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; | ||
447 | world.UpdateSingleAabb(body); | ||
448 | } | ||
449 | |||
450 | internal static bool SetCollisionGroupMask2(object pBody, uint pGroup, uint pMask) | ||
451 | { | ||
452 | RigidBody body = pBody as RigidBody; | ||
453 | body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; | ||
454 | body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; | ||
455 | if ((uint) body.GetBroadphaseHandle().m_collisionFilterGroup == 0) | ||
456 | return false; | ||
457 | return true; | ||
458 | } | ||
459 | |||
460 | internal static void ClearAllForces2(object pBody) | ||
461 | { | ||
462 | CollisionObject body = pBody as CollisionObject; | ||
463 | IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0); | ||
464 | body.SetInterpolationLinearVelocity(ref zeroVector); | ||
465 | body.SetInterpolationAngularVelocity(ref zeroVector); | ||
466 | IndexedMatrix bodytransform = body.GetWorldTransform(); | ||
467 | |||
468 | body.SetInterpolationWorldTransform(ref bodytransform); | ||
469 | |||
470 | if (body is RigidBody) | ||
471 | { | ||
472 | RigidBody rigidbody = body as RigidBody; | ||
473 | rigidbody.SetLinearVelocity(zeroVector); | ||
474 | rigidbody.SetAngularVelocity(zeroVector); | ||
475 | rigidbody.ClearForces(); | ||
476 | } | ||
477 | } | ||
478 | |||
479 | internal static void SetInterpolationAngularVelocity2(object pBody, Vector3 pVector3) | ||
480 | { | ||
481 | RigidBody body = pBody as RigidBody; | ||
482 | IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); | ||
483 | body.SetInterpolationAngularVelocity(ref vec); | ||
484 | } | ||
485 | |||
486 | internal static void SetAngularVelocity2(object pBody, Vector3 pVector3) | ||
487 | { | ||
488 | RigidBody body = pBody as RigidBody; | ||
489 | IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); | ||
490 | body.SetAngularVelocity(ref vec); | ||
491 | } | ||
492 | |||
493 | internal static void ClearForces2(object pBody) | ||
494 | { | ||
495 | RigidBody body = pBody as RigidBody; | ||
496 | body.ClearForces(); | ||
497 | } | ||
498 | |||
499 | internal static void SetTranslation2(object pBody, Vector3 _position, Quaternion _orientation) | ||
500 | { | ||
501 | RigidBody body = pBody as RigidBody; | ||
502 | IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z); | ||
503 | IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z, | ||
504 | _orientation.W); | ||
505 | IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); | ||
506 | mat._origin = vposition; | ||
507 | body.SetWorldTransform(mat); | ||
508 | |||
509 | } | ||
510 | |||
511 | internal static Vector3 GetPosition2(object pBody) | ||
512 | { | ||
513 | RigidBody body = pBody as RigidBody; | ||
514 | IndexedVector3 pos = body.GetInterpolationWorldTransform()._origin; | ||
515 | return new Vector3(pos.X, pos.Y, pos.Z); | ||
516 | } | ||
517 | |||
518 | internal static Vector3 CalculateLocalInertia2(object pShape, float pphysMass) | ||
519 | { | ||
520 | CollisionShape shape = pShape as CollisionShape; | ||
521 | IndexedVector3 inertia = IndexedVector3.Zero; | ||
522 | shape.CalculateLocalInertia(pphysMass, out inertia); | ||
523 | return new Vector3(inertia.X, inertia.Y, inertia.Z); | ||
524 | } | ||
525 | |||
526 | internal static void SetMassProps2(object pBody, float pphysMass, Vector3 plocalInertia) | ||
527 | { | ||
528 | RigidBody body = pBody as RigidBody; | ||
529 | IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z); | ||
530 | body.SetMassProps(pphysMass, inertia); | ||
531 | } | ||
532 | |||
533 | |||
534 | internal static void SetObjectForce2(object pBody, Vector3 _force) | ||
535 | { | ||
536 | RigidBody body = pBody as RigidBody; | ||
537 | IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z); | ||
538 | body.SetTotalForce(ref force); | ||
539 | } | ||
540 | |||
541 | internal static void SetFriction2(object pBody, float _currentFriction) | ||
542 | { | ||
543 | RigidBody body = pBody as RigidBody; | ||
544 | body.SetFriction(_currentFriction); | ||
545 | } | ||
546 | |||
547 | internal static void SetLinearVelocity2(object pBody, Vector3 _velocity) | ||
548 | { | ||
549 | RigidBody body = pBody as RigidBody; | ||
550 | IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z); | ||
551 | body.SetLinearVelocity(velocity); | ||
552 | } | ||
553 | |||
554 | internal static void Activate2(object pBody, bool pforceactivation) | ||
555 | { | ||
556 | RigidBody body = pBody as RigidBody; | ||
557 | body.Activate(pforceactivation); | ||
558 | |||
559 | } | ||
560 | |||
561 | internal static Quaternion GetOrientation2(object pBody) | ||
562 | { | ||
563 | RigidBody body = pBody as RigidBody; | ||
564 | IndexedQuaternion mat = body.GetInterpolationWorldTransform().GetRotation(); | ||
565 | return new Quaternion(mat.X, mat.Y, mat.Z, mat.W); | ||
566 | } | ||
567 | |||
568 | internal static CollisionFlags RemoveFromCollisionFlags2(object pBody, CollisionFlags pcollisionFlags) | ||
569 | { | ||
570 | RigidBody body = pBody as RigidBody; | ||
571 | CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags(); | ||
572 | existingcollisionFlags &= ~pcollisionFlags; | ||
573 | body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); | ||
574 | return (CollisionFlags)(uint)existingcollisionFlags; | ||
575 | } | ||
576 | |||
577 | internal static void SetGravity2(object pBody, Vector3 pGravity) | ||
578 | { | ||
579 | RigidBody body = pBody as RigidBody; | ||
580 | IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z); | ||
581 | body.SetGravity(gravity); | ||
582 | } | ||
583 | |||
584 | internal static bool DestroyConstraint2(object pBody, object pConstraint) | ||
585 | { | ||
586 | RigidBody body = pBody as RigidBody; | ||
587 | TypedConstraint constraint = pConstraint as TypedConstraint; | ||
588 | body.RemoveConstraintRef(constraint); | ||
589 | return true; | ||
590 | } | ||
591 | |||
592 | internal static bool SetLinearLimits2(object pConstraint, Vector3 low, Vector3 high) | ||
593 | { | ||
594 | Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; | ||
595 | IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); | ||
596 | IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); | ||
597 | constraint.SetLinearLowerLimit(lowlimit); | ||
598 | constraint.SetLinearUpperLimit(highlimit); | ||
599 | return true; | ||
600 | } | ||
601 | |||
602 | internal static bool SetAngularLimits2(object pConstraint, Vector3 low, Vector3 high) | ||
603 | { | ||
604 | Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; | ||
605 | IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); | ||
606 | IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); | ||
607 | constraint.SetAngularLowerLimit(lowlimit); | ||
608 | constraint.SetAngularUpperLimit(highlimit); | ||
609 | return true; | ||
610 | } | ||
611 | |||
612 | internal static void SetConstraintNumSolverIterations2(object pConstraint, float cnt) | ||
613 | { | ||
614 | Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; | ||
615 | constraint.SetOverrideNumSolverIterations((int)cnt); | ||
616 | } | ||
617 | |||
618 | internal static void CalculateTransforms2(object pConstraint) | ||
619 | { | ||
620 | Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; | ||
621 | constraint.CalculateTransforms(); | ||
622 | } | ||
623 | |||
624 | internal static void SetConstraintEnable2(object pConstraint, float p_2) | ||
625 | { | ||
626 | Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; | ||
627 | constraint.SetEnabled((p_2 == 0) ? false : true); | ||
628 | } | ||
629 | |||
630 | |||
631 | //BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,frame1, frame1rot,frame2, frame2rot,useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
632 | internal static object Create6DofConstraint2(object pWorld, object pBody1, object pBody2, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
633 | |||
634 | { | ||
635 | DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; | ||
636 | RigidBody body1 = pBody1 as RigidBody; | ||
637 | RigidBody body2 = pBody2 as RigidBody; | ||
638 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
639 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
640 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
641 | frame1._origin = frame1v; | ||
642 | |||
643 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
644 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
645 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
646 | frame2._origin = frame1v; | ||
647 | |||
648 | Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, | ||
649 | puseLinearReferenceFrameA); | ||
650 | consttr.CalculateTransforms(); | ||
651 | world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); | ||
652 | |||
653 | return consttr; | ||
654 | } | ||
655 | |||
656 | |||
657 | /// <summary> | ||
658 | /// | ||
659 | /// </summary> | ||
660 | /// <param name="pWorld"></param> | ||
661 | /// <param name="pBody1"></param> | ||
662 | /// <param name="pBody2"></param> | ||
663 | /// <param name="pjoinPoint"></param> | ||
664 | /// <param name="puseLinearReferenceFrameA"></param> | ||
665 | /// <param name="pdisableCollisionsBetweenLinkedBodies"></param> | ||
666 | /// <returns></returns> | ||
667 | internal static object Create6DofConstraintToPoint2(object pWorld, object pBody1, object pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
668 | { | ||
669 | DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; | ||
670 | RigidBody body1 = pBody1 as RigidBody; | ||
671 | RigidBody body2 = pBody2 as RigidBody; | ||
672 | IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); | ||
673 | IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); | ||
674 | |||
675 | IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); | ||
676 | IndexedMatrix mat = IndexedMatrix.Identity; | ||
677 | mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); | ||
678 | frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint; | ||
679 | frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint; | ||
680 | |||
681 | Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); | ||
682 | consttr.CalculateTransforms(); | ||
683 | world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies); | ||
684 | |||
685 | return consttr; | ||
686 | } | ||
687 | //SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); | ||
688 | internal static void SetFrames2(object pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot) | ||
689 | { | ||
690 | Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; | ||
691 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
692 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
693 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
694 | frame1._origin = frame1v; | ||
695 | |||
696 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
697 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
698 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
699 | frame2._origin = frame1v; | ||
700 | constraint.SetFrames(ref frame1, ref frame2); | ||
701 | } | ||
702 | |||
703 | |||
704 | |||
705 | |||
706 | internal static bool IsInWorld2(object pWorld, object pShapeObj) | ||
707 | { | ||
708 | DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; | ||
709 | CollisionObject shape = pShapeObj as CollisionObject; | ||
710 | return world.IsInWorld(shape); | ||
711 | } | ||
712 | |||
713 | internal static void SetInterpolationLinearVelocity2(object pBody, Vector3 VehicleVelocity) | ||
714 | { | ||
715 | RigidBody body = pBody as RigidBody; | ||
716 | IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z); | ||
717 | body.SetInterpolationLinearVelocity(ref velocity); | ||
718 | } | ||
719 | |||
720 | internal static bool UseFrameOffset2(object pConstraint, float onOff) | ||
721 | { | ||
722 | Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; | ||
723 | constraint.SetUseFrameOffset((onOff == 0) ? false : true); | ||
724 | return true; | ||
725 | } | ||
726 | //SetBreakingImpulseThreshold2(m_constraint.ptr, threshold); | ||
727 | internal static bool SetBreakingImpulseThreshold2(object pConstraint, float threshold) | ||
728 | { | ||
729 | Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; | ||
730 | constraint.SetBreakingImpulseThreshold(threshold); | ||
731 | return true; | ||
732 | } | ||
733 | //BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); | ||
734 | internal static void SetAngularDamping2(object pBody, float angularDamping) | ||
735 | { | ||
736 | RigidBody body = pBody as RigidBody; | ||
737 | float lineardamping = body.GetLinearDamping(); | ||
738 | body.SetDamping(lineardamping, angularDamping); | ||
739 | |||
740 | } | ||
741 | |||
742 | internal static void UpdateInertiaTensor2(object pBody) | ||
743 | { | ||
744 | RigidBody body = pBody as RigidBody; | ||
745 | body.UpdateInertiaTensor(); | ||
746 | } | ||
747 | |||
748 | internal static void RecalculateCompoundShapeLocalAabb2( object pCompoundShape) | ||
749 | { | ||
750 | |||
751 | CompoundShape shape = pCompoundShape as CompoundShape; | ||
752 | shape.RecalculateLocalAabb(); | ||
753 | } | ||
754 | |||
755 | //BulletSimAPI.GetCollisionFlags2(PhysBody.ptr) | ||
756 | internal static CollisionFlags GetCollisionFlags2(object pBody) | ||
757 | { | ||
758 | RigidBody body = pBody as RigidBody; | ||
759 | uint flags = (uint)body.GetCollisionFlags(); | ||
760 | return (CollisionFlags) flags; | ||
761 | } | ||
762 | |||
763 | internal static void SetDamping2(object pBody, float pLinear, float pAngular) | ||
764 | { | ||
765 | RigidBody body = pBody as RigidBody; | ||
766 | body.SetDamping(pLinear, pAngular); | ||
767 | } | ||
768 | //PhysBody.ptr, PhysicsScene.Params.deactivationTime); | ||
769 | internal static void SetDeactivationTime2(object pBody, float pDeactivationTime) | ||
770 | { | ||
771 | RigidBody body = pBody as RigidBody; | ||
772 | body.SetDeactivationTime(pDeactivationTime); | ||
773 | } | ||
774 | //SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); | ||
775 | internal static void SetSleepingThresholds2(object pBody, float plinearSleepingThreshold, float pangularSleepingThreshold) | ||
776 | { | ||
777 | RigidBody body = pBody as RigidBody; | ||
778 | body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold); | ||
779 | } | ||
780 | |||
781 | internal static CollisionObjectTypes GetBodyType2(object pBody) | ||
782 | { | ||
783 | RigidBody body = pBody as RigidBody; | ||
784 | return (CollisionObjectTypes)(int) body.GetInternalType(); | ||
785 | } | ||
786 | |||
787 | //BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); | ||
788 | internal static void ApplyCentralForce2(object pBody, Vector3 pfSum) | ||
789 | { | ||
790 | RigidBody body = pBody as RigidBody; | ||
791 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
792 | body.ApplyCentralForce(ref fSum); | ||
793 | } | ||
794 | internal static void ApplyCentralImpulse2(object pBody, Vector3 pfSum) | ||
795 | { | ||
796 | RigidBody body = pBody as RigidBody; | ||
797 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
798 | body.ApplyCentralImpulse(ref fSum); | ||
799 | } | ||
800 | internal static void ApplyTorque2(object pBody, Vector3 pfSum) | ||
801 | { | ||
802 | RigidBody body = pBody as RigidBody; | ||
803 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
804 | body.ApplyTorque(ref fSum); | ||
805 | } | ||
806 | internal static void ApplyTorqueImpulse2(object pBody, Vector3 pfSum) | ||
807 | { | ||
808 | RigidBody body = pBody as RigidBody; | ||
809 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
810 | body.ApplyTorqueImpulse(ref fSum); | ||
811 | } | ||
812 | |||
813 | internal static void DumpRigidBody2(object p, object p_2) | ||
814 | { | ||
815 | //TODO: | ||
816 | } | ||
817 | |||
818 | internal static void DumpCollisionShape2(object p, object p_2) | ||
819 | { | ||
820 | //TODO: | ||
821 | } | ||
822 | |||
823 | internal static void DestroyObject2(object p, object p_2) | ||
824 | { | ||
825 | //TODO: | ||
826 | } | ||
827 | |||
828 | internal static void Shutdown2(object pWorld) | ||
829 | { | ||
830 | DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; | ||
831 | world.Cleanup(); | ||
832 | } | ||
833 | |||
834 | internal static void DeleteCollisionShape2(object p, object p_2) | ||
835 | { | ||
836 | //TODO: | ||
837 | } | ||
838 | //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); | ||
839 | |||
840 | internal static object CreateBodyFromShape2(object pWorld, object pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | ||
841 | { | ||
842 | CollisionWorld world = pWorld as CollisionWorld; | ||
843 | IndexedMatrix mat = | ||
844 | IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, | ||
845 | pRawOrientation.Z, pRawOrientation.W)); | ||
846 | mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | ||
847 | CollisionShape shape = pShape as CollisionShape; | ||
848 | //UpdateSingleAabb2(world, shape); | ||
849 | // TODO: Feed Update array into null | ||
850 | RigidBody body = new RigidBody(0,new SimMotionState(world,pLocalID,mat,null),shape,IndexedVector3.Zero); | ||
851 | |||
852 | body.SetUserPointer(pLocalID); | ||
853 | return body; | ||
854 | } | ||
855 | |||
856 | |||
857 | internal static object CreateBodyWithDefaultMotionState2( object pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | ||
858 | { | ||
859 | |||
860 | IndexedMatrix mat = | ||
861 | IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, | ||
862 | pRawOrientation.Z, pRawOrientation.W)); | ||
863 | mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | ||
864 | |||
865 | CollisionShape shape = pShape as CollisionShape; | ||
866 | |||
867 | // TODO: Feed Update array into null | ||
868 | RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero); | ||
869 | body.SetWorldTransform(mat); | ||
870 | body.SetUserPointer(pLocalID); | ||
871 | return body; | ||
872 | } | ||
873 | //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
874 | internal static void SetCollisionFlags2(object pBody, CollisionFlags collisionFlags) | ||
875 | { | ||
876 | RigidBody body = pBody as RigidBody; | ||
877 | body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags); | ||
878 | } | ||
879 | //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); | ||
880 | internal static void SetHitFraction2(object pBody, float pHitFraction) | ||
881 | { | ||
882 | RigidBody body = pBody as RigidBody; | ||
883 | body.SetHitFraction(pHitFraction); | ||
884 | } | ||
885 | //BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale); | ||
886 | internal static object BuildCapsuleShape2(object pWorld, float pRadius, float pHeight, Vector3 pScale) | ||
887 | { | ||
888 | DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; | ||
889 | IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); | ||
890 | CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight); | ||
891 | capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
892 | capsuleShapeZ.SetLocalScaling(ref scale); | ||
893 | |||
894 | return capsuleShapeZ; | ||
895 | } | ||
896 | |||
897 | public static object Initialize2(Vector3 worldExtent, ConfigurationParameters[] o, int mMaxCollisionsPerFrame, ref List<BulletXNA.CollisionDesc> collisionArray, int mMaxUpdatesPerFrame, ref List<BulletXNA.EntityProperties> updateArray, object mDebugLogCallbackHandle) | ||
898 | { | ||
899 | CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); | ||
900 | |||
901 | p.angularDamping = o[0].XangularDamping; | ||
902 | p.defaultFriction = o[0].defaultFriction; | ||
903 | p.defaultFriction = o[0].defaultFriction; | ||
904 | p.defaultDensity = o[0].defaultDensity; | ||
905 | p.defaultRestitution = o[0].defaultRestitution; | ||
906 | p.collisionMargin = o[0].collisionMargin; | ||
907 | p.gravity = o[0].gravity; | ||
908 | |||
909 | p.linearDamping = o[0].XlinearDamping; | ||
910 | p.angularDamping = o[0].XangularDamping; | ||
911 | p.deactivationTime = o[0].XdeactivationTime; | ||
912 | p.linearSleepingThreshold = o[0].XlinearSleepingThreshold; | ||
913 | p.angularSleepingThreshold = o[0].XangularSleepingThreshold; | ||
914 | p.ccdMotionThreshold = o[0].XccdMotionThreshold; | ||
915 | p.ccdSweptSphereRadius = o[0].XccdSweptSphereRadius; | ||
916 | p.contactProcessingThreshold = o[0].XcontactProcessingThreshold; | ||
917 | |||
918 | p.terrainImplementation = o[0].XterrainImplementation; | ||
919 | p.terrainFriction = o[0].XterrainFriction; | ||
920 | |||
921 | p.terrainHitFraction = o[0].XterrainHitFraction; | ||
922 | p.terrainRestitution = o[0].XterrainRestitution; | ||
923 | p.terrainCollisionMargin = o[0].XterrainCollisionMargin; | ||
924 | |||
925 | p.avatarFriction = o[0].XavatarFriction; | ||
926 | p.avatarStandingFriction = o[0].XavatarStandingFriction; | ||
927 | p.avatarDensity = o[0].XavatarDensity; | ||
928 | p.avatarRestitution = o[0].XavatarRestitution; | ||
929 | p.avatarCapsuleWidth = o[0].XavatarCapsuleWidth; | ||
930 | p.avatarCapsuleDepth = o[0].XavatarCapsuleDepth; | ||
931 | p.avatarCapsuleHeight = o[0].XavatarCapsuleHeight; | ||
932 | p.avatarContactProcessingThreshold = o[0].XavatarContactProcessingThreshold; | ||
933 | |||
934 | p.vehicleAngularDamping = o[0].XvehicleAngularDamping; | ||
935 | |||
936 | p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; | ||
937 | p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; | ||
938 | p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; | ||
939 | p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs; | ||
940 | p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder; | ||
941 | p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands; | ||
942 | p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching; | ||
943 | p.numberOfSolverIterations = o[0].numberOfSolverIterations; | ||
944 | |||
945 | p.linksetImplementation = o[0].XlinksetImplementation; | ||
946 | p.linkConstraintUseFrameOffset = o[0].XlinkConstraintUseFrameOffset; | ||
947 | p.linkConstraintEnableTransMotor = o[0].XlinkConstraintEnableTransMotor; | ||
948 | p.linkConstraintTransMotorMaxVel = o[0].XlinkConstraintTransMotorMaxVel; | ||
949 | p.linkConstraintTransMotorMaxForce = o[0].XlinkConstraintTransMotorMaxForce; | ||
950 | p.linkConstraintERP = o[0].XlinkConstraintERP; | ||
951 | p.linkConstraintCFM = o[0].XlinkConstraintCFM; | ||
952 | p.linkConstraintSolverIterations = o[0].XlinkConstraintSolverIterations; | ||
953 | p.physicsLoggingFrames = o[0].physicsLoggingFrames; | ||
954 | DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); | ||
955 | |||
956 | DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); | ||
957 | CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); | ||
958 | |||
959 | |||
960 | if (p.maxPersistantManifoldPoolSize > 0) | ||
961 | cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize; | ||
962 | if (p.shouldDisableContactPoolDynamicAllocation !=0) | ||
963 | m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION); | ||
964 | //if (p.maxCollisionAlgorithmPoolSize >0 ) | ||
965 | |||
966 | DbvtBroadphase m_broadphase = new DbvtBroadphase(); | ||
967 | //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0); | ||
968 | //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256); | ||
969 | |||
970 | //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true); | ||
971 | m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback()); | ||
972 | |||
973 | SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver(); | ||
974 | |||
975 | DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci); | ||
976 | world.UpdatedObjects = updateArray; | ||
977 | world.UpdatedCollisions = collisionArray; | ||
978 | world.WorldSettings.Params = p; | ||
979 | world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0); | ||
980 | world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD; | ||
981 | if (p.shouldRandomizeSolverOrder != 0) | ||
982 | world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER; | ||
983 | |||
984 | world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0); | ||
985 | //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port | ||
986 | |||
987 | if (p.shouldEnableFrictionCaching != 0) | ||
988 | world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING; | ||
989 | |||
990 | if (p.numberOfSolverIterations > 0) | ||
991 | world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations; | ||
992 | |||
993 | |||
994 | world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping; | ||
995 | world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution; | ||
996 | world.GetSolverInfo().m_globalCfm = 0.0f; | ||
997 | world.GetSolverInfo().m_tau = 0.6f; | ||
998 | world.GetSolverInfo().m_friction = 0.3f; | ||
999 | world.GetSolverInfo().m_maxErrorReduction = 20f; | ||
1000 | world.GetSolverInfo().m_numIterations = 10; | ||
1001 | world.GetSolverInfo().m_erp = 0.2f; | ||
1002 | world.GetSolverInfo().m_erp2 = 0.1f; | ||
1003 | world.GetSolverInfo().m_sor = 1.0f; | ||
1004 | world.GetSolverInfo().m_splitImpulse = false; | ||
1005 | world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f; | ||
1006 | world.GetSolverInfo().m_linearSlop = 0.0f; | ||
1007 | world.GetSolverInfo().m_warmstartingFactor = 0.85f; | ||
1008 | world.GetSolverInfo().m_restingContactRestitutionThreshold = 2; | ||
1009 | world.SetForceUpdateAllAabbs(true); | ||
1010 | |||
1011 | |||
1012 | world.SetGravity(new IndexedVector3(0,0,p.gravity)); | ||
1013 | |||
1014 | return world; | ||
1015 | } | ||
1016 | //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL | ||
1017 | internal static bool SetConstraintParam2(object pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis) | ||
1018 | { | ||
1019 | Generic6DofConstraint constrain = pConstraint as Generic6DofConstraint; | ||
1020 | if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) | ||
1021 | { | ||
1022 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0); | ||
1023 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1); | ||
1024 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2); | ||
1025 | } | ||
1026 | if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) | ||
1027 | { | ||
1028 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3); | ||
1029 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4); | ||
1030 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5); | ||
1031 | } | ||
1032 | if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL) | ||
1033 | { | ||
1034 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis); | ||
1035 | } | ||
1036 | return true; | ||
1037 | } | ||
1038 | |||
1039 | internal static bool PushUpdate2(object pCollisionObject) | ||
1040 | { | ||
1041 | bool ret = false; | ||
1042 | RigidBody rb = pCollisionObject as RigidBody; | ||
1043 | if (rb != null) | ||
1044 | { | ||
1045 | SimMotionState sms = rb.GetMotionState() as SimMotionState; | ||
1046 | if (sms != null) | ||
1047 | { | ||
1048 | IndexedMatrix wt = IndexedMatrix.Identity; | ||
1049 | sms.GetWorldTransform(out wt); | ||
1050 | sms.SetWorldTransform(ref wt, true); | ||
1051 | ret = true; | ||
1052 | } | ||
1053 | } | ||
1054 | return ret; | ||
1055 | |||
1056 | } | ||
1057 | |||
1058 | internal static bool IsCompound2(object pShape) | ||
1059 | { | ||
1060 | CollisionShape shape = pShape as CollisionShape; | ||
1061 | return shape.IsCompound(); | ||
1062 | } | ||
1063 | internal static bool IsPloyhedral2(object pShape) | ||
1064 | { | ||
1065 | CollisionShape shape = pShape as CollisionShape; | ||
1066 | return shape.IsPolyhedral(); | ||
1067 | } | ||
1068 | internal static bool IsConvex2d2(object pShape) | ||
1069 | { | ||
1070 | CollisionShape shape = pShape as CollisionShape; | ||
1071 | return shape.IsConvex2d(); | ||
1072 | } | ||
1073 | internal static bool IsConvex2(object pShape) | ||
1074 | { | ||
1075 | CollisionShape shape = pShape as CollisionShape; | ||
1076 | return shape.IsConvex(); | ||
1077 | } | ||
1078 | internal static bool IsNonMoving2(object pShape) | ||
1079 | { | ||
1080 | CollisionShape shape = pShape as CollisionShape; | ||
1081 | return shape.IsNonMoving(); | ||
1082 | } | ||
1083 | internal static bool IsConcave2(object pShape) | ||
1084 | { | ||
1085 | CollisionShape shape = pShape as CollisionShape; | ||
1086 | return shape.IsConcave(); | ||
1087 | } | ||
1088 | internal static bool IsInfinite2(object pShape) | ||
1089 | { | ||
1090 | CollisionShape shape = pShape as CollisionShape; | ||
1091 | return shape.IsInfinite(); | ||
1092 | } | ||
1093 | internal static bool IsNativeShape2(object pShape) | ||
1094 | { | ||
1095 | CollisionShape shape = pShape as CollisionShape; | ||
1096 | bool ret; | ||
1097 | switch (shape.GetShapeType()) | ||
1098 | { | ||
1099 | case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: | ||
1100 | case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: | ||
1101 | case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: | ||
1102 | case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: | ||
1103 | ret = true; | ||
1104 | break; | ||
1105 | default: | ||
1106 | ret = false; | ||
1107 | break; | ||
1108 | } | ||
1109 | return ret; | ||
1110 | } | ||
1111 | //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation | ||
1112 | internal static object CreateGhostFromShape2(object pWorld, object pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | ||
1113 | { | ||
1114 | IndexedMatrix bodyTransform = new IndexedMatrix(); | ||
1115 | bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | ||
1116 | bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W)); | ||
1117 | GhostObject gObj = new PairCachingGhostObject(); | ||
1118 | gObj.SetWorldTransform(bodyTransform); | ||
1119 | CollisionShape shape = pShape as CollisionShape; | ||
1120 | gObj.SetCollisionShape(shape); | ||
1121 | gObj.SetUserPointer(pLocalID); | ||
1122 | // TODO: Add to Special CollisionObjects! | ||
1123 | return gObj; | ||
1124 | } | ||
1125 | |||
1126 | public static void SetCollisionShape2(object pWorld, object pObj, object pShape) | ||
1127 | { | ||
1128 | var world = pWorld as DiscreteDynamicsWorld; | ||
1129 | var obj = pObj as CollisionObject; | ||
1130 | var shape = pShape as CollisionShape; | ||
1131 | obj.SetCollisionShape(shape); | ||
1132 | |||
1133 | } | ||
1134 | //(PhysicsScene.World.ptr, nativeShapeData) | ||
1135 | internal static object BuildNativeShape2(object pWorld, ShapeData pShapeData) | ||
1136 | { | ||
1137 | var world = pWorld as DiscreteDynamicsWorld; | ||
1138 | CollisionShape shape = null; | ||
1139 | switch (pShapeData.Type) | ||
1140 | { | ||
1141 | case BSPhysicsShapeType.SHAPE_BOX: | ||
1142 | shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f)); | ||
1143 | break; | ||
1144 | case BSPhysicsShapeType.SHAPE_CONE: | ||
1145 | shape = new ConeShapeZ(0.5f, 1.0f); | ||
1146 | break; | ||
1147 | case BSPhysicsShapeType.SHAPE_CYLINDER: | ||
1148 | shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f)); | ||
1149 | break; | ||
1150 | case BSPhysicsShapeType.SHAPE_SPHERE: | ||
1151 | shape = new SphereShape(0.5f); | ||
1152 | break; | ||
1153 | |||
1154 | } | ||
1155 | if (shape != null) | ||
1156 | { | ||
1157 | IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z); | ||
1158 | shape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1159 | shape.SetLocalScaling(ref scaling); | ||
1160 | |||
1161 | } | ||
1162 | return shape; | ||
1163 | } | ||
1164 | //PhysicsScene.World.ptr, false | ||
1165 | internal static object CreateCompoundShape2(object pWorld, bool enableDynamicAabbTree) | ||
1166 | { | ||
1167 | return new CompoundShape(enableDynamicAabbTree); | ||
1168 | } | ||
1169 | |||
1170 | internal static int GetNumberOfCompoundChildren2(object pCompoundShape) | ||
1171 | { | ||
1172 | var compoundshape = pCompoundShape as CompoundShape; | ||
1173 | return compoundshape.GetNumChildShapes(); | ||
1174 | } | ||
1175 | //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot | ||
1176 | internal static void AddChildShapeToCompoundShape2(object pCShape, object paddShape, Vector3 displacementPos, Quaternion displacementRot) | ||
1177 | { | ||
1178 | IndexedMatrix relativeTransform = new IndexedMatrix(); | ||
1179 | var compoundshape = pCShape as CompoundShape; | ||
1180 | var addshape = paddShape as CollisionShape; | ||
1181 | |||
1182 | relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z); | ||
1183 | relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W)); | ||
1184 | compoundshape.AddChildShape(ref relativeTransform, addshape); | ||
1185 | |||
1186 | } | ||
1187 | |||
1188 | internal static object RemoveChildShapeFromCompoundShapeIndex2(object pCShape, int pii) | ||
1189 | { | ||
1190 | var compoundshape = pCShape as CompoundShape; | ||
1191 | CollisionShape ret = null; | ||
1192 | ret = compoundshape.GetChildShape(pii); | ||
1193 | compoundshape.RemoveChildShapeByIndex(pii); | ||
1194 | return ret; | ||
1195 | } | ||
1196 | |||
1197 | internal static object CreateGroundPlaneShape2(uint pLocalId, float pheight, float pcollisionMargin) | ||
1198 | { | ||
1199 | StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight ); | ||
1200 | m_planeshape.SetMargin(pcollisionMargin); | ||
1201 | m_planeshape.SetUserPointer(pLocalId); | ||
1202 | return m_planeshape; | ||
1203 | } | ||
1204 | |||
1205 | internal static object CreateHingeConstraint2(object pWorld, object pBody1, object ppBody2, Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
1206 | { | ||
1207 | HingeConstraint constrain = null; | ||
1208 | var rb1 = pBody1 as RigidBody; | ||
1209 | var rb2 = ppBody2 as RigidBody; | ||
1210 | if (rb1 != null && rb2 != null) | ||
1211 | { | ||
1212 | IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); | ||
1213 | IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); | ||
1214 | IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); | ||
1215 | IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); | ||
1216 | var world = pWorld as DiscreteDynamicsWorld; | ||
1217 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1218 | } | ||
1219 | return constrain; | ||
1220 | } | ||
1221 | |||
1222 | internal static bool ReleaseHeightMapInfo2(object pMapInfo) | ||
1223 | { | ||
1224 | if (pMapInfo != null) | ||
1225 | { | ||
1226 | BulletHeightMapInfo mapinfo = pMapInfo as BulletHeightMapInfo; | ||
1227 | if (mapinfo.heightMap != null) | ||
1228 | mapinfo.heightMap = null; | ||
1229 | |||
1230 | |||
1231 | } | ||
1232 | return true; | ||
1233 | } | ||
1234 | |||
1235 | internal static object CreateHullShape2(object pWorld, int pHullCount, float[] pConvHulls) | ||
1236 | { | ||
1237 | CompoundShape compoundshape = new CompoundShape(false); | ||
1238 | var world = pWorld as DiscreteDynamicsWorld; | ||
1239 | |||
1240 | |||
1241 | compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1242 | int ii = 1; | ||
1243 | |||
1244 | for (int i = 0; i < pHullCount; i++) | ||
1245 | { | ||
1246 | int vertexCount = (int) pConvHulls[ii]; | ||
1247 | |||
1248 | IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]); | ||
1249 | IndexedMatrix childTrans = IndexedMatrix.Identity; | ||
1250 | childTrans._origin = centroid; | ||
1251 | |||
1252 | List<IndexedVector3> virts = new List<IndexedVector3>(); | ||
1253 | int ender = ((ii + 4) + (vertexCount*3)); | ||
1254 | for (int iii = ii + 4; iii < ender; iii+=3) | ||
1255 | { | ||
1256 | |||
1257 | virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); | ||
1258 | } | ||
1259 | ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); | ||
1260 | convexShape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1261 | compoundshape.AddChildShape(ref childTrans, convexShape); | ||
1262 | ii += (vertexCount*3 + 4); | ||
1263 | } | ||
1264 | |||
1265 | |||
1266 | return compoundshape; | ||
1267 | } | ||
1268 | |||
1269 | internal static object CreateMeshShape2(object pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | ||
1270 | { | ||
1271 | //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); | ||
1272 | |||
1273 | for (int iter = 0; iter < pVerticesCount; iter++) | ||
1274 | { | ||
1275 | if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; | ||
1276 | if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; | ||
1277 | } | ||
1278 | |||
1279 | ObjectArray<int> indicesarr = new ObjectArray<int>(indices); | ||
1280 | ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); | ||
1281 | DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); | ||
1282 | var world = pWorld as DiscreteDynamicsWorld; | ||
1283 | IndexedMesh mesh = new IndexedMesh(); | ||
1284 | mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; | ||
1285 | mesh.m_numTriangles = pIndicesCount/3; | ||
1286 | mesh.m_numVertices = pVerticesCount; | ||
1287 | mesh.m_triangleIndexBase = indicesarr; | ||
1288 | mesh.m_vertexBase = vertices; | ||
1289 | mesh.m_vertexStride = 3; | ||
1290 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | ||
1291 | mesh.m_triangleIndexStride = 3; | ||
1292 | |||
1293 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | ||
1294 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | ||
1295 | BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); | ||
1296 | meshShape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1297 | // world.UpdateSingleAabb(meshShape); | ||
1298 | return meshShape; | ||
1299 | |||
1300 | } | ||
1301 | public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) | ||
1302 | { | ||
1303 | |||
1304 | String fileName = "objTest3.raw"; | ||
1305 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); | ||
1306 | StreamWriter sw = new StreamWriter(completePath); | ||
1307 | IndexedMesh mesh = new IndexedMesh(); | ||
1308 | |||
1309 | mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; | ||
1310 | mesh.m_numTriangles = pIndicesCount / 3; | ||
1311 | mesh.m_numVertices = pVerticesCount; | ||
1312 | mesh.m_triangleIndexBase = indices; | ||
1313 | mesh.m_vertexBase = vertices; | ||
1314 | mesh.m_vertexStride = 3; | ||
1315 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | ||
1316 | mesh.m_triangleIndexStride = 3; | ||
1317 | |||
1318 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | ||
1319 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | ||
1320 | |||
1321 | |||
1322 | |||
1323 | for (int i = 0; i < pVerticesCount; i++) | ||
1324 | { | ||
1325 | |||
1326 | string s = vertices[indices[i * 3]].ToString("0.0000"); | ||
1327 | s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); | ||
1328 | s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); | ||
1329 | |||
1330 | sw.Write(s + "\n"); | ||
1331 | } | ||
1332 | |||
1333 | sw.Close(); | ||
1334 | } | ||
1335 | public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount) | ||
1336 | { | ||
1337 | |||
1338 | String fileName = "objTest6.raw"; | ||
1339 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); | ||
1340 | StreamWriter sw = new StreamWriter(completePath); | ||
1341 | IndexedMesh mesh = new IndexedMesh(); | ||
1342 | |||
1343 | mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; | ||
1344 | mesh.m_numTriangles = pIndicesCount / 3; | ||
1345 | mesh.m_numVertices = pVerticesCount; | ||
1346 | mesh.m_triangleIndexBase = indices; | ||
1347 | mesh.m_vertexBase = vertices; | ||
1348 | mesh.m_vertexStride = 3; | ||
1349 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | ||
1350 | mesh.m_triangleIndexStride = 3; | ||
1351 | |||
1352 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | ||
1353 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | ||
1354 | |||
1355 | |||
1356 | sw.WriteLine("Indices"); | ||
1357 | sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount)); | ||
1358 | for (int iter = 0; iter < indices.Length; iter++) | ||
1359 | { | ||
1360 | sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter])); | ||
1361 | } | ||
1362 | sw.WriteLine("VerticesFloats"); | ||
1363 | sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount)); | ||
1364 | for (int iter = 0; iter < vertices.Length; iter++) | ||
1365 | { | ||
1366 | sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000"))); | ||
1367 | } | ||
1368 | |||
1369 | // for (int i = 0; i < pVerticesCount; i++) | ||
1370 | // { | ||
1371 | // | ||
1372 | // string s = vertices[indices[i * 3]].ToString("0.0000"); | ||
1373 | // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); | ||
1374 | // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); | ||
1375 | // | ||
1376 | // sw.Write(s + "\n"); | ||
1377 | //} | ||
1378 | |||
1379 | sw.Close(); | ||
1380 | } | ||
1381 | //PhysicsScene.World.ptr, m_mapInfo.ID, m_mapInfo.minCoords, m_mapInfo.maxCoords, m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin | ||
1382 | internal static object CreateHeightMapInfo2(object pWorld, uint pId, Vector3 pminCoords, Vector3 pmaxCoords, float[] pheightMap, float pCollisionMargin) | ||
1383 | { | ||
1384 | BulletHeightMapInfo mapInfo = new BulletHeightMapInfo(pId, pheightMap, null); | ||
1385 | mapInfo.heightMap = null; | ||
1386 | mapInfo.minCoords = pminCoords; | ||
1387 | mapInfo.maxCoords = pmaxCoords; | ||
1388 | mapInfo.sizeX = (int) (pmaxCoords.X - pminCoords.X); | ||
1389 | mapInfo.sizeY = (int) (pmaxCoords.Y - pminCoords.Y); | ||
1390 | mapInfo.ID = pId; | ||
1391 | mapInfo.minZ = pminCoords.Z; | ||
1392 | mapInfo.maxZ = pmaxCoords.Z; | ||
1393 | mapInfo.collisionMargin = pCollisionMargin; | ||
1394 | if (mapInfo.minZ == mapInfo.maxZ) | ||
1395 | mapInfo.minZ -= 0.2f; | ||
1396 | mapInfo.heightMap = pheightMap; | ||
1397 | |||
1398 | return mapInfo; | ||
1399 | |||
1400 | } | ||
1401 | |||
1402 | internal static object CreateTerrainShape2(object pMapInfo) | ||
1403 | { | ||
1404 | BulletHeightMapInfo mapinfo = pMapInfo as BulletHeightMapInfo; | ||
1405 | const int upAxis = 2; | ||
1406 | const float scaleFactor = 1.0f; | ||
1407 | HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)mapinfo.sizeX, (int)mapinfo.sizeY, | ||
1408 | mapinfo.heightMap, scaleFactor, | ||
1409 | mapinfo.minZ, mapinfo.maxZ, upAxis, | ||
1410 | false); | ||
1411 | terrainShape.SetMargin(mapinfo.collisionMargin + 0.5f); | ||
1412 | terrainShape.SetUseDiamondSubdivision(true); | ||
1413 | terrainShape.SetUserPointer(mapinfo.ID); | ||
1414 | return terrainShape; | ||
1415 | } | ||
1416 | |||
1417 | internal static bool TranslationalLimitMotor2(object pConstraint, float ponOff, float targetVelocity, float maxMotorForce) | ||
1418 | { | ||
1419 | TypedConstraint tconstrain = pConstraint as TypedConstraint; | ||
1420 | bool onOff = ponOff != 0; | ||
1421 | bool ret = false; | ||
1422 | |||
1423 | switch (tconstrain.GetConstraintType()) | ||
1424 | { | ||
1425 | case TypedConstraintType.D6_CONSTRAINT_TYPE: | ||
1426 | Generic6DofConstraint constrain = pConstraint as Generic6DofConstraint; | ||
1427 | constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff; | ||
1428 | constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity; | ||
1429 | constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce; | ||
1430 | ret = true; | ||
1431 | break; | ||
1432 | } | ||
1433 | |||
1434 | |||
1435 | return ret; | ||
1436 | |||
1437 | } | ||
1438 | |||
1439 | internal static int PhysicsStep2(object pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, out int collidersCount, out List<BulletXNA.CollisionDesc>colliders) | ||
1440 | { | ||
1441 | int epic = PhysicsStepint2(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities, | ||
1442 | out collidersCount, out colliders); | ||
1443 | return epic; | ||
1444 | } | ||
1445 | |||
1446 | private static int PhysicsStepint2(object pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, out int collidersCount, out List<BulletXNA.CollisionDesc> colliders) | ||
1447 | { | ||
1448 | int numSimSteps = 0; | ||
1449 | |||
1450 | |||
1451 | //if (updatedEntities is null) | ||
1452 | // updatedEntities = new List<BulletXNA.EntityProperties>(); | ||
1453 | |||
1454 | //if (colliders is null) | ||
1455 | // colliders = new List<BulletXNA.CollisionDesc>(); | ||
1456 | |||
1457 | |||
1458 | if (pWorld is DiscreteDynamicsWorld) | ||
1459 | { | ||
1460 | DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; | ||
1461 | |||
1462 | numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep); | ||
1463 | int updates = 0; | ||
1464 | |||
1465 | updatedEntityCount = world.UpdatedObjects.Count; | ||
1466 | updatedEntities = new List<BulletXNA.EntityProperties>(world.UpdatedObjects); | ||
1467 | updatedEntityCount = updatedEntities.Count; | ||
1468 | world.UpdatedObjects.Clear(); | ||
1469 | |||
1470 | |||
1471 | collidersCount = world.UpdatedCollisions.Count; | ||
1472 | colliders = new List<BulletXNA.CollisionDesc>(world.UpdatedCollisions); | ||
1473 | |||
1474 | world.UpdatedCollisions.Clear(); | ||
1475 | m_collisionsThisFrame = 0; | ||
1476 | int numManifolds = world.GetDispatcher().GetNumManifolds(); | ||
1477 | for (int j = 0; j < numManifolds; j++) | ||
1478 | { | ||
1479 | PersistentManifold contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j); | ||
1480 | int numContacts = contactManifold.GetNumContacts(); | ||
1481 | if (numContacts == 0) | ||
1482 | continue; | ||
1483 | |||
1484 | CollisionObject objA = contactManifold.GetBody0() as CollisionObject; | ||
1485 | CollisionObject objB = contactManifold.GetBody1() as CollisionObject; | ||
1486 | |||
1487 | ManifoldPoint manifoldPoint = contactManifold.GetContactPoint(0); | ||
1488 | IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB(); | ||
1489 | IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A | ||
1490 | |||
1491 | RecordCollision(world, objA, objB, contactPoint, contactNormal); | ||
1492 | m_collisionsThisFrame ++; | ||
1493 | if (m_collisionsThisFrame >= 9999999) | ||
1494 | break; | ||
1495 | |||
1496 | |||
1497 | } | ||
1498 | |||
1499 | |||
1500 | } | ||
1501 | else | ||
1502 | { | ||
1503 | //if (updatedEntities is null) | ||
1504 | updatedEntities = new List<BulletXNA.EntityProperties>(); | ||
1505 | updatedEntityCount = 0; | ||
1506 | //if (colliders is null) | ||
1507 | colliders = new List<BulletXNA.CollisionDesc>(); | ||
1508 | collidersCount = 0; | ||
1509 | } | ||
1510 | return numSimSteps; | ||
1511 | } | ||
1512 | |||
1513 | private static void RecordCollision(CollisionWorld world,CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm) | ||
1514 | { | ||
1515 | |||
1516 | IndexedVector3 contactNormal = norm; | ||
1517 | if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && | ||
1518 | (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) | ||
1519 | { | ||
1520 | return; | ||
1521 | } | ||
1522 | uint idA = (uint)objA.GetUserPointer(); | ||
1523 | uint idB = (uint)objB.GetUserPointer(); | ||
1524 | if (idA > idB) | ||
1525 | { | ||
1526 | uint temp = idA; | ||
1527 | idA = idB; | ||
1528 | idB = temp; | ||
1529 | contactNormal = -contactNormal; | ||
1530 | } | ||
1531 | |||
1532 | ulong collisionID = ((ulong) idA << 32) | idB; | ||
1533 | |||
1534 | BulletXNA.CollisionDesc cDesc = new BulletXNA.CollisionDesc() | ||
1535 | { | ||
1536 | aID = idA, | ||
1537 | bID = idB, | ||
1538 | point = contact, | ||
1539 | normal = contactNormal | ||
1540 | }; | ||
1541 | world.UpdatedCollisions.Add(cDesc); | ||
1542 | m_collisionsThisFrame++; | ||
1543 | |||
1544 | |||
1545 | } | ||
1546 | private static EntityProperties GetDebugProperties(object pWorld, object pBody) | ||
1547 | { | ||
1548 | EntityProperties ent = new EntityProperties(); | ||
1549 | DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; | ||
1550 | RigidBody body = pBody as RigidBody; | ||
1551 | IndexedMatrix transform = body.GetWorldTransform(); | ||
1552 | IndexedVector3 LinearVelocity = body.GetInterpolationLinearVelocity(); | ||
1553 | IndexedVector3 AngularVelocity = body.GetInterpolationAngularVelocity(); | ||
1554 | IndexedQuaternion rotation = transform.GetRotation(); | ||
1555 | ent.Acceleration = Vector3.Zero; | ||
1556 | ent.ID = (uint)body.GetUserPointer(); | ||
1557 | ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z); | ||
1558 | ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W); | ||
1559 | ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z); | ||
1560 | ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z); | ||
1561 | return ent; | ||
1562 | |||
1563 | |||
1564 | } | ||
1565 | |||
1566 | |||
1567 | internal static Vector3 GetLocalScaling2(object pBody) | ||
1568 | { | ||
1569 | CollisionShape shape = pBody as CollisionShape; | ||
1570 | IndexedVector3 scale = shape.GetLocalScaling(); | ||
1571 | return new Vector3(scale.X,scale.Y,scale.Z); | ||
1572 | } | ||
1573 | |||
1574 | internal static bool RayCastGround(object pWorld, Vector3 _RayOrigin, float pRayHeight, object NotMe) | ||
1575 | { | ||
1576 | DynamicsWorld world = pWorld as DynamicsWorld; | ||
1577 | if (world != null) | ||
1578 | { | ||
1579 | if (NotMe is CollisionObject || NotMe is RigidBody) | ||
1580 | { | ||
1581 | CollisionObject AvoidBody = NotMe as CollisionObject; | ||
1582 | |||
1583 | IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); | ||
1584 | IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); | ||
1585 | using ( | ||
1586 | ClosestNotMeRayResultCallback rayCallback = new ClosestNotMeRayResultCallback(rOrigin, | ||
1587 | rEnd, AvoidBody) | ||
1588 | ) | ||
1589 | { | ||
1590 | world.RayTest(ref rOrigin, ref rEnd, rayCallback); | ||
1591 | if (rayCallback.HasHit()) | ||
1592 | { | ||
1593 | IndexedVector3 hitLocation = rayCallback.m_hitPointWorld; | ||
1594 | |||
1595 | } | ||
1596 | return rayCallback.HasHit(); | ||
1597 | } | ||
1598 | } | ||
1599 | } | ||
1600 | return false; | ||
1601 | } | ||
1602 | } | ||
1603 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs new file mode 100644 index 0000000..f509dc4 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs | |||
@@ -0,0 +1,280 @@ | |||
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.BulletSNPlugin | ||
33 | { | ||
34 | // Classes to allow some type checking for the API | ||
35 | // These hold pointers to allocated objects in the unmanaged space. | ||
36 | |||
37 | // The physics engine controller class created at initialization | ||
38 | public struct BulletWorld | ||
39 | { | ||
40 | public BulletWorld(uint worldId, BSScene bss, object xx) | ||
41 | { | ||
42 | ptr = xx; | ||
43 | worldID = worldId; | ||
44 | physicsScene = bss; | ||
45 | } | ||
46 | public object ptr; | ||
47 | public uint worldID; | ||
48 | // The scene is only in here so very low level routines have a handle to print debug/error messages | ||
49 | public BSScene physicsScene; | ||
50 | } | ||
51 | |||
52 | // An allocated Bullet btRigidBody | ||
53 | public struct BulletBody | ||
54 | { | ||
55 | public BulletBody(uint id) : this(id, null) | ||
56 | { | ||
57 | } | ||
58 | public BulletBody(uint id, object xx) | ||
59 | { | ||
60 | ID = id; | ||
61 | ptr = xx; | ||
62 | collisionType = CollisionType.Static; | ||
63 | } | ||
64 | public object ptr; | ||
65 | public uint ID; | ||
66 | public CollisionType collisionType; | ||
67 | |||
68 | public void Clear() | ||
69 | { | ||
70 | ptr = null; | ||
71 | } | ||
72 | public bool HasPhysicalBody { get { return ptr != null; } } | ||
73 | |||
74 | // Apply the specificed collision mask into the physical world | ||
75 | public void ApplyCollisionMask() | ||
76 | { | ||
77 | // Should assert the body has been added to the physical world. | ||
78 | // (The collision masks are stored in the collision proxy cache which only exists for | ||
79 | // a collision body that is in the world.) | ||
80 | BulletSimAPI.SetCollisionGroupMask2(ptr, | ||
81 | BulletSimData.CollisionTypeMasks[collisionType].group, | ||
82 | BulletSimData.CollisionTypeMasks[collisionType].mask); | ||
83 | } | ||
84 | |||
85 | public override string ToString() | ||
86 | { | ||
87 | StringBuilder buff = new StringBuilder(); | ||
88 | buff.Append("<id="); | ||
89 | buff.Append(ID.ToString()); | ||
90 | buff.Append(",p="); | ||
91 | buff.Append(ptr.ToString()); | ||
92 | buff.Append(",c="); | ||
93 | buff.Append(collisionType); | ||
94 | buff.Append(">"); | ||
95 | return buff.ToString(); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | public struct BulletShape | ||
100 | { | ||
101 | public BulletShape(object xx) : this(xx, BSPhysicsShapeType.SHAPE_UNKNOWN) | ||
102 | { | ||
103 | } | ||
104 | public BulletShape(object xx, BSPhysicsShapeType typ) | ||
105 | { | ||
106 | ptr = xx; | ||
107 | type = typ; | ||
108 | shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; | ||
109 | isNativeShape = false; | ||
110 | } | ||
111 | public object ptr; | ||
112 | public BSPhysicsShapeType type; | ||
113 | public System.UInt64 shapeKey; | ||
114 | public bool isNativeShape; | ||
115 | |||
116 | public void Clear() | ||
117 | { | ||
118 | ptr = null; | ||
119 | } | ||
120 | public bool HasPhysicalShape { get { return ptr != null; } } | ||
121 | |||
122 | public override string ToString() | ||
123 | { | ||
124 | StringBuilder buff = new StringBuilder(); | ||
125 | buff.Append("<p="); | ||
126 | buff.Append(ptr.ToString()); | ||
127 | buff.Append(",s="); | ||
128 | buff.Append(type.ToString()); | ||
129 | buff.Append(",k="); | ||
130 | buff.Append(shapeKey.ToString("X")); | ||
131 | buff.Append(",n="); | ||
132 | buff.Append(isNativeShape.ToString()); | ||
133 | buff.Append(">"); | ||
134 | return buff.ToString(); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | // An allocated Bullet btConstraint | ||
139 | public struct BulletConstraint | ||
140 | { | ||
141 | public BulletConstraint(object xx) | ||
142 | { | ||
143 | ptr = xx; | ||
144 | } | ||
145 | public object ptr; | ||
146 | |||
147 | public void Clear() | ||
148 | { | ||
149 | ptr = null; | ||
150 | } | ||
151 | public bool HasPhysicalConstraint { get { return ptr != null; } } | ||
152 | } | ||
153 | |||
154 | // An allocated HeightMapThing which holds various heightmap info. | ||
155 | // Made a class rather than a struct so there would be only one | ||
156 | // instance of this and C# will pass around pointers rather | ||
157 | // than making copies. | ||
158 | public class BulletHeightMapInfo | ||
159 | { | ||
160 | public BulletHeightMapInfo(uint id, float[] hm, object xx) { | ||
161 | ID = id; | ||
162 | Ptr = xx; | ||
163 | heightMap = hm; | ||
164 | terrainRegionBase = OMV.Vector3.Zero; | ||
165 | minCoords = new OMV.Vector3(100f, 100f, 25f); | ||
166 | maxCoords = new OMV.Vector3(101f, 101f, 26f); | ||
167 | minZ = maxZ = 0f; | ||
168 | sizeX = sizeY = 256f; | ||
169 | } | ||
170 | public uint ID; | ||
171 | public object Ptr; | ||
172 | public float[] heightMap; | ||
173 | public OMV.Vector3 terrainRegionBase; | ||
174 | public OMV.Vector3 minCoords; | ||
175 | public OMV.Vector3 maxCoords; | ||
176 | public float sizeX, sizeY; | ||
177 | public float minZ, maxZ; | ||
178 | public BulletShape terrainShape; | ||
179 | public BulletBody terrainBody; | ||
180 | |||
181 | public float collisionMargin { get; set; } | ||
182 | } | ||
183 | |||
184 | // The general class of collsion object. | ||
185 | public enum CollisionType | ||
186 | { | ||
187 | Avatar, | ||
188 | Groundplane, | ||
189 | Terrain, | ||
190 | Static, | ||
191 | Dynamic, | ||
192 | VolumeDetect, | ||
193 | // Linkset, // A linkset should be either Static or Dynamic | ||
194 | LinksetChild, | ||
195 | Unknown | ||
196 | }; | ||
197 | |||
198 | // Hold specification of group and mask collision flags for a CollisionType | ||
199 | public struct CollisionTypeFilterGroup | ||
200 | { | ||
201 | public CollisionTypeFilterGroup(CollisionType t, uint g, uint m) | ||
202 | { | ||
203 | type = t; | ||
204 | group = g; | ||
205 | mask = m; | ||
206 | } | ||
207 | public CollisionType type; | ||
208 | public uint group; | ||
209 | public uint mask; | ||
210 | }; | ||
211 | |||
212 | /* NOTE: old definitions kept for reference. Delete when things are working. | ||
213 | // The collsion filters and masked are defined in one place -- don't want them scattered | ||
214 | AvatarGroup = BCharacterGroup, | ||
215 | AvatarMask = BAllGroup, | ||
216 | ObjectGroup = BSolidGroup, | ||
217 | ObjectMask = BAllGroup, | ||
218 | StaticObjectGroup = BStaticGroup, | ||
219 | StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much | ||
220 | LinksetGroup = BLinksetGroup, | ||
221 | LinksetMask = BAllGroup, | ||
222 | LinksetChildGroup = BLinksetChildGroup, | ||
223 | LinksetChildMask = BNoneGroup, // Linkset children disappear from the world | ||
224 | VolumeDetectGroup = BSensorTrigger, | ||
225 | VolumeDetectMask = ~BSensorTrigger, | ||
226 | TerrainGroup = BTerrainGroup, | ||
227 | TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide | ||
228 | GroundPlaneGroup = BGroundPlaneGroup, | ||
229 | GroundPlaneMask = BAllGroup | ||
230 | */ | ||
231 | |||
232 | public static class BulletSimData | ||
233 | { | ||
234 | |||
235 | // Map of collisionTypes to flags for collision groups and masks. | ||
236 | // As mentioned above, don't use the CollisionFilterGroups definitions directly in the code | ||
237 | // but, instead, use references to this dictionary. Finding and debugging | ||
238 | // collision flag problems will be made easier. | ||
239 | public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks | ||
240 | = new Dictionary<CollisionType, CollisionTypeFilterGroup>() | ||
241 | { | ||
242 | { CollisionType.Avatar, | ||
243 | new CollisionTypeFilterGroup(CollisionType.Avatar, | ||
244 | (uint)CollisionFilterGroups.BCharacterGroup, | ||
245 | (uint)CollisionFilterGroups.BAllGroup) | ||
246 | }, | ||
247 | { CollisionType.Groundplane, | ||
248 | new CollisionTypeFilterGroup(CollisionType.Groundplane, | ||
249 | (uint)CollisionFilterGroups.BGroundPlaneGroup, | ||
250 | (uint)CollisionFilterGroups.BAllGroup) | ||
251 | }, | ||
252 | { CollisionType.Terrain, | ||
253 | new CollisionTypeFilterGroup(CollisionType.Terrain, | ||
254 | (uint)CollisionFilterGroups.BTerrainGroup, | ||
255 | (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) | ||
256 | }, | ||
257 | { CollisionType.Static, | ||
258 | new CollisionTypeFilterGroup(CollisionType.Static, | ||
259 | (uint)CollisionFilterGroups.BStaticGroup, | ||
260 | (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | ||
261 | }, | ||
262 | { CollisionType.Dynamic, | ||
263 | new CollisionTypeFilterGroup(CollisionType.Dynamic, | ||
264 | (uint)CollisionFilterGroups.BSolidGroup, | ||
265 | (uint)(CollisionFilterGroups.BAllGroup)) | ||
266 | }, | ||
267 | { CollisionType.VolumeDetect, | ||
268 | new CollisionTypeFilterGroup(CollisionType.VolumeDetect, | ||
269 | (uint)CollisionFilterGroups.BSensorTrigger, | ||
270 | (uint)(~CollisionFilterGroups.BSensorTrigger)) | ||
271 | }, | ||
272 | { CollisionType.LinksetChild, | ||
273 | new CollisionTypeFilterGroup(CollisionType.LinksetChild, | ||
274 | (uint)CollisionFilterGroups.BTerrainGroup, | ||
275 | (uint)(CollisionFilterGroups.BNoneGroup)) | ||
276 | }, | ||
277 | }; | ||
278 | |||
279 | } | ||
280 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs new file mode 100755 index 0000000..14de2eb --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs | |||
@@ -0,0 +1,1863 @@ | |||
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 | type = 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, type); | ||
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 | |||
217 | public override bool PushUpdate(BulletBody obj) | ||
218 | { | ||
219 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
220 | return BSAPICPP.PushUpdate2(bodyu.ptr); | ||
221 | } | ||
222 | |||
223 | public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) | ||
224 | { | ||
225 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
226 | return BSAPICPP.UpdateParameter2(worldu.ptr, localID, parm, value); | ||
227 | } | ||
228 | |||
229 | // ===================================================================================== | ||
230 | // Mesh, hull, shape and body creation helper routines | ||
231 | public override BulletShape CreateMeshShape(BulletWorld world, | ||
232 | int indicesCount, int[] indices, | ||
233 | int verticesCount, float[] vertices) | ||
234 | { | ||
235 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
236 | return new BulletShapeUnman( | ||
237 | BSAPICPP.CreateMeshShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), | ||
238 | BSPhysicsShapeType.SHAPE_MESH); | ||
239 | } | ||
240 | |||
241 | public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) | ||
242 | { | ||
243 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
244 | return new BulletShapeUnman( | ||
245 | BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), | ||
246 | BSPhysicsShapeType.SHAPE_HULL); | ||
247 | } | ||
248 | |||
249 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | ||
250 | { | ||
251 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
252 | BulletShapeUnman shapeu = meshShape as BulletShapeUnman; | ||
253 | return new BulletShapeUnman( | ||
254 | BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr), | ||
255 | BSPhysicsShapeType.SHAPE_HULL); | ||
256 | } | ||
257 | |||
258 | public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) | ||
259 | { | ||
260 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
261 | return new BulletShapeUnman(BSAPICPP.BuildNativeShape2(worldu.ptr, shapeData), shapeData.Type); | ||
262 | } | ||
263 | |||
264 | public override bool IsNativeShape(BulletShape shape) | ||
265 | { | ||
266 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
267 | if (shapeu != null && shapeu.HasPhysicalShape) | ||
268 | return BSAPICPP.IsNativeShape2(shapeu.ptr); | ||
269 | return false; | ||
270 | } | ||
271 | |||
272 | public override void SetShapeCollisionMargin(BulletShape shape, float margin) | ||
273 | { | ||
274 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
275 | if (shapeu != null && shapeu.HasPhysicalShape) | ||
276 | BSAPICPP.SetShapeCollisionMargin2(shapeu.ptr, margin); | ||
277 | } | ||
278 | |||
279 | public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) | ||
280 | { | ||
281 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
282 | return new BulletShapeUnman( | ||
283 | BSAPICPP.BuildCapsuleShape2(worldu.ptr, radius, height, scale), | ||
284 | BSPhysicsShapeType.SHAPE_CAPSULE); | ||
285 | } | ||
286 | |||
287 | public override BulletShape CreateCompoundShape(BulletWorld world, bool enableDynamicAabbTree) | ||
288 | { | ||
289 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
290 | return new BulletShapeUnman( | ||
291 | BSAPICPP.CreateCompoundShape2(worldu.ptr, enableDynamicAabbTree), | ||
292 | BSPhysicsShapeType.SHAPE_COMPOUND); | ||
293 | |||
294 | } | ||
295 | |||
296 | public override int GetNumberOfCompoundChildren(BulletShape shape) | ||
297 | { | ||
298 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
299 | if (shapeu != null && shapeu.HasPhysicalShape) | ||
300 | return BSAPICPP.GetNumberOfCompoundChildren2(shapeu.ptr); | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | public override void AddChildShapeToCompoundShape(BulletShape shape, BulletShape addShape, Vector3 pos, Quaternion rot) | ||
305 | { | ||
306 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
307 | BulletShapeUnman addShapeu = addShape as BulletShapeUnman; | ||
308 | BSAPICPP.AddChildShapeToCompoundShape2(shapeu.ptr, addShapeu.ptr, pos, rot); | ||
309 | } | ||
310 | |||
311 | public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape shape, int indx) | ||
312 | { | ||
313 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
314 | return new BulletShapeUnman(BSAPICPP.GetChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN); | ||
315 | } | ||
316 | |||
317 | public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape shape, int indx) | ||
318 | { | ||
319 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
320 | return new BulletShapeUnman(BSAPICPP.RemoveChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN); | ||
321 | } | ||
322 | |||
323 | public override void RemoveChildShapeFromCompoundShape(BulletShape shape, BulletShape removeShape) | ||
324 | { | ||
325 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
326 | BulletShapeUnman removeShapeu = removeShape as BulletShapeUnman; | ||
327 | BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr); | ||
328 | } | ||
329 | |||
330 | public override void RecalculateCompoundShapeLocalAabb(BulletShape shape) | ||
331 | { | ||
332 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
333 | BSAPICPP.RecalculateCompoundShapeLocalAabb2(shapeu.ptr); | ||
334 | } | ||
335 | |||
336 | public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletShape srcShape, uint id) | ||
337 | { | ||
338 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
339 | BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; | ||
340 | return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type); | ||
341 | } | ||
342 | |||
343 | public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) | ||
344 | { | ||
345 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
346 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
347 | return BSAPICPP.DeleteCollisionShape2(worldu.ptr, shapeu.ptr); | ||
348 | } | ||
349 | |||
350 | public override CollisionObjectTypes GetBodyType(BulletBody obj) | ||
351 | { | ||
352 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
353 | return (CollisionObjectTypes)BSAPICPP.GetBodyType2(bodyu.ptr); | ||
354 | } | ||
355 | |||
356 | public override BulletBody CreateBodyFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot) | ||
357 | { | ||
358 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
359 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
360 | return new BulletBodyUnman(id, BSAPICPP.CreateBodyFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot)); | ||
361 | } | ||
362 | |||
363 | public override BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot) | ||
364 | { | ||
365 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
366 | return new BulletBodyUnman(id, BSAPICPP.CreateBodyWithDefaultMotionState2(shapeu.ptr, id, pos, rot)); | ||
367 | } | ||
368 | |||
369 | public override BulletBody CreateGhostFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot) | ||
370 | { | ||
371 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
372 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
373 | return new BulletBodyUnman(id, BSAPICPP.CreateGhostFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot)); | ||
374 | } | ||
375 | |||
376 | public override void DestroyObject(BulletWorld world, BulletBody obj) | ||
377 | { | ||
378 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
379 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
380 | BSAPICPP.DestroyObject2(worldu.ptr, bodyu.ptr); | ||
381 | } | ||
382 | |||
383 | // ===================================================================================== | ||
384 | // Terrain creation and helper routines | ||
385 | public override BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin) | ||
386 | { | ||
387 | return new BulletShapeUnman(BSAPICPP.CreateGroundPlaneShape2(id, height, collisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE); | ||
388 | } | ||
389 | |||
390 | public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | ||
391 | float scaleFactor, float collisionMargin) | ||
392 | { | ||
393 | return new BulletShapeUnman(BSAPICPP.CreateTerrainShape2(id, size, minHeight, maxHeight, heightMap, scaleFactor, collisionMargin), | ||
394 | BSPhysicsShapeType.SHAPE_TERRAIN); | ||
395 | } | ||
396 | |||
397 | // ===================================================================================== | ||
398 | // Constraint creation and helper routines | ||
399 | public override BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
400 | Vector3 frame1loc, Quaternion frame1rot, | ||
401 | Vector3 frame2loc, Quaternion frame2rot, | ||
402 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
403 | { | ||
404 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
405 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
406 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
407 | return new BulletConstraintUnman(BSAPICPP.Create6DofConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, | ||
408 | frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
409 | } | ||
410 | |||
411 | public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
412 | Vector3 joinPoint, | ||
413 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
414 | { | ||
415 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
416 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
417 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
418 | return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintToPoint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, | ||
419 | joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
420 | } | ||
421 | |||
422 | public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
423 | Vector3 pivotinA, Vector3 pivotinB, | ||
424 | Vector3 axisInA, Vector3 axisInB, | ||
425 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
426 | { | ||
427 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
428 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
429 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
430 | return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, | ||
431 | pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
432 | } | ||
433 | |||
434 | public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse) | ||
435 | { | ||
436 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
437 | BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse); | ||
438 | } | ||
439 | |||
440 | public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations) | ||
441 | { | ||
442 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
443 | BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations); | ||
444 | } | ||
445 | |||
446 | public override bool SetFrames(BulletConstraint constrain, | ||
447 | Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) | ||
448 | { | ||
449 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
450 | return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot); | ||
451 | } | ||
452 | |||
453 | public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi) | ||
454 | { | ||
455 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
456 | return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi); | ||
457 | } | ||
458 | |||
459 | public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi) | ||
460 | { | ||
461 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
462 | return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi); | ||
463 | } | ||
464 | |||
465 | public override bool UseFrameOffset(BulletConstraint constrain, float enable) | ||
466 | { | ||
467 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
468 | return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable); | ||
469 | } | ||
470 | |||
471 | public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce) | ||
472 | { | ||
473 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
474 | return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce); | ||
475 | } | ||
476 | |||
477 | public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold) | ||
478 | { | ||
479 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
480 | return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold); | ||
481 | } | ||
482 | |||
483 | public override bool CalculateTransforms(BulletConstraint constrain) | ||
484 | { | ||
485 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
486 | return BSAPICPP.CalculateTransforms2(constrainu.ptr); | ||
487 | } | ||
488 | |||
489 | public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis) | ||
490 | { | ||
491 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
492 | return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis); | ||
493 | } | ||
494 | |||
495 | public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain) | ||
496 | { | ||
497 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
498 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
499 | return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr); | ||
500 | } | ||
501 | |||
502 | // ===================================================================================== | ||
503 | // btCollisionWorld entries | ||
504 | public override void UpdateSingleAabb(BulletWorld world, BulletBody obj) | ||
505 | { | ||
506 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
507 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
508 | BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr); | ||
509 | } | ||
510 | |||
511 | public override void UpdateAabbs(BulletWorld world) | ||
512 | { | ||
513 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
514 | BSAPICPP.UpdateAabbs2(worldu.ptr); | ||
515 | } | ||
516 | |||
517 | public override bool GetForceUpdateAllAabbs(BulletWorld world) | ||
518 | { | ||
519 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
520 | return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr); | ||
521 | } | ||
522 | |||
523 | public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) | ||
524 | { | ||
525 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
526 | BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force); | ||
527 | } | ||
528 | |||
529 | // ===================================================================================== | ||
530 | // btDynamicsWorld entries | ||
531 | public override bool AddObjectToWorld(BulletWorld world, BulletBody obj) | ||
532 | { | ||
533 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
534 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
535 | |||
536 | // Bullet resets several variables when an object is added to the world. | ||
537 | // Gravity is reset to world default depending on the static/dynamic | ||
538 | // type. Of course, the collision flags in the broadphase proxy are initialized to default. | ||
539 | Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr); | ||
540 | |||
541 | bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr); | ||
542 | |||
543 | if (ret) | ||
544 | { | ||
545 | BSAPICPP.SetGravity2(bodyu.ptr, origGrav); | ||
546 | obj.ApplyCollisionMask(world.physicsScene); | ||
547 | } | ||
548 | return ret; | ||
549 | } | ||
550 | |||
551 | public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj) | ||
552 | { | ||
553 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
554 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
555 | return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr); | ||
556 | } | ||
557 | |||
558 | public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) | ||
559 | { | ||
560 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
561 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
562 | return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects); | ||
563 | } | ||
564 | |||
565 | public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain) | ||
566 | { | ||
567 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
568 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
569 | return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr); | ||
570 | } | ||
571 | // ===================================================================================== | ||
572 | // btCollisionObject entries | ||
573 | public override Vector3 GetAnisotripicFriction(BulletConstraint constrain) | ||
574 | { | ||
575 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
576 | return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr); | ||
577 | } | ||
578 | |||
579 | public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict) | ||
580 | { | ||
581 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
582 | return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict); | ||
583 | } | ||
584 | |||
585 | public override bool HasAnisotripicFriction(BulletConstraint constrain) | ||
586 | { | ||
587 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
588 | return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr); | ||
589 | } | ||
590 | |||
591 | public override void SetContactProcessingThreshold(BulletBody obj, float val) | ||
592 | { | ||
593 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
594 | BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val); | ||
595 | } | ||
596 | |||
597 | public override float GetContactProcessingThreshold(BulletBody obj) | ||
598 | { | ||
599 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
600 | return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr); | ||
601 | } | ||
602 | |||
603 | public override bool IsStaticObject(BulletBody obj) | ||
604 | { | ||
605 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
606 | return BSAPICPP.IsStaticObject2(bodyu.ptr); | ||
607 | } | ||
608 | |||
609 | public override bool IsKinematicObject(BulletBody obj) | ||
610 | { | ||
611 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
612 | return BSAPICPP.IsKinematicObject2(bodyu.ptr); | ||
613 | } | ||
614 | |||
615 | public override bool IsStaticOrKinematicObject(BulletBody obj) | ||
616 | { | ||
617 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
618 | return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr); | ||
619 | } | ||
620 | |||
621 | public override bool HasContactResponse(BulletBody obj) | ||
622 | { | ||
623 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
624 | return BSAPICPP.HasContactResponse2(bodyu.ptr); | ||
625 | } | ||
626 | |||
627 | public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape) | ||
628 | { | ||
629 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
630 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
631 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
632 | if (worldu != null && bodyu != null) | ||
633 | { | ||
634 | // Special case to allow the caller to zero out the reference to any physical shape | ||
635 | if (shapeu != null) | ||
636 | BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr); | ||
637 | else | ||
638 | BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero); | ||
639 | } | ||
640 | } | ||
641 | |||
642 | public override BulletShape GetCollisionShape(BulletBody obj) | ||
643 | { | ||
644 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
645 | return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN); | ||
646 | } | ||
647 | |||
648 | public override int GetActivationState(BulletBody obj) | ||
649 | { | ||
650 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
651 | return BSAPICPP.GetActivationState2(bodyu.ptr); | ||
652 | } | ||
653 | |||
654 | public override void SetActivationState(BulletBody obj, int state) | ||
655 | { | ||
656 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
657 | BSAPICPP.SetActivationState2(bodyu.ptr, state); | ||
658 | } | ||
659 | |||
660 | public override void SetDeactivationTime(BulletBody obj, float dtime) | ||
661 | { | ||
662 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
663 | BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime); | ||
664 | } | ||
665 | |||
666 | public override float GetDeactivationTime(BulletBody obj) | ||
667 | { | ||
668 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
669 | return BSAPICPP.GetDeactivationTime2(bodyu.ptr); | ||
670 | } | ||
671 | |||
672 | public override void ForceActivationState(BulletBody obj, ActivationState state) | ||
673 | { | ||
674 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
675 | BSAPICPP.ForceActivationState2(bodyu.ptr, state); | ||
676 | } | ||
677 | |||
678 | public override void Activate(BulletBody obj, bool forceActivation) | ||
679 | { | ||
680 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
681 | BSAPICPP.Activate2(bodyu.ptr, forceActivation); | ||
682 | } | ||
683 | |||
684 | public override bool IsActive(BulletBody obj) | ||
685 | { | ||
686 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
687 | return BSAPICPP.IsActive2(bodyu.ptr); | ||
688 | } | ||
689 | |||
690 | public override void SetRestitution(BulletBody obj, float val) | ||
691 | { | ||
692 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
693 | BSAPICPP.SetRestitution2(bodyu.ptr, val); | ||
694 | } | ||
695 | |||
696 | public override float GetRestitution(BulletBody obj) | ||
697 | { | ||
698 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
699 | return BSAPICPP.GetRestitution2(bodyu.ptr); | ||
700 | } | ||
701 | |||
702 | public override void SetFriction(BulletBody obj, float val) | ||
703 | { | ||
704 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
705 | BSAPICPP.SetFriction2(bodyu.ptr, val); | ||
706 | } | ||
707 | |||
708 | public override float GetFriction(BulletBody obj) | ||
709 | { | ||
710 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
711 | return BSAPICPP.GetFriction2(bodyu.ptr); | ||
712 | } | ||
713 | |||
714 | public override Vector3 GetPosition(BulletBody obj) | ||
715 | { | ||
716 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
717 | return BSAPICPP.GetPosition2(bodyu.ptr); | ||
718 | } | ||
719 | |||
720 | public override Quaternion GetOrientation(BulletBody obj) | ||
721 | { | ||
722 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
723 | return BSAPICPP.GetOrientation2(bodyu.ptr); | ||
724 | } | ||
725 | |||
726 | public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation) | ||
727 | { | ||
728 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
729 | BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation); | ||
730 | } | ||
731 | |||
732 | /* | ||
733 | public override IntPtr GetBroadphaseHandle(BulletBody obj) | ||
734 | { | ||
735 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
736 | return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr); | ||
737 | } | ||
738 | |||
739 | public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle) | ||
740 | { | ||
741 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
742 | BSAPICPP.SetUserPointer2(bodyu.ptr, handle); | ||
743 | } | ||
744 | */ | ||
745 | |||
746 | public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel) | ||
747 | { | ||
748 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
749 | BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel); | ||
750 | } | ||
751 | |||
752 | public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel) | ||
753 | { | ||
754 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
755 | BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel); | ||
756 | } | ||
757 | |||
758 | public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel) | ||
759 | { | ||
760 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
761 | BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel); | ||
762 | } | ||
763 | |||
764 | public override float GetHitFraction(BulletBody obj) | ||
765 | { | ||
766 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
767 | return BSAPICPP.GetHitFraction2(bodyu.ptr); | ||
768 | } | ||
769 | |||
770 | public override void SetHitFraction(BulletBody obj, float val) | ||
771 | { | ||
772 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
773 | BSAPICPP.SetHitFraction2(bodyu.ptr, val); | ||
774 | } | ||
775 | |||
776 | public override CollisionFlags GetCollisionFlags(BulletBody obj) | ||
777 | { | ||
778 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
779 | return BSAPICPP.GetCollisionFlags2(bodyu.ptr); | ||
780 | } | ||
781 | |||
782 | public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags) | ||
783 | { | ||
784 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
785 | return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags); | ||
786 | } | ||
787 | |||
788 | public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags) | ||
789 | { | ||
790 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
791 | return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags); | ||
792 | } | ||
793 | |||
794 | public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags) | ||
795 | { | ||
796 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
797 | return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags); | ||
798 | } | ||
799 | |||
800 | public override float GetCcdMotionThreshold(BulletBody obj) | ||
801 | { | ||
802 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
803 | return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr); | ||
804 | } | ||
805 | |||
806 | |||
807 | public override void SetCcdMotionThreshold(BulletBody obj, float val) | ||
808 | { | ||
809 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
810 | BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val); | ||
811 | } | ||
812 | |||
813 | public override float GetCcdSweptSphereRadius(BulletBody obj) | ||
814 | { | ||
815 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
816 | return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr); | ||
817 | } | ||
818 | |||
819 | public override void SetCcdSweptSphereRadius(BulletBody obj, float val) | ||
820 | { | ||
821 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
822 | BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val); | ||
823 | } | ||
824 | |||
825 | public override IntPtr GetUserPointer(BulletBody obj) | ||
826 | { | ||
827 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
828 | return BSAPICPP.GetUserPointer2(bodyu.ptr); | ||
829 | } | ||
830 | |||
831 | public override void SetUserPointer(BulletBody obj, IntPtr val) | ||
832 | { | ||
833 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
834 | BSAPICPP.SetUserPointer2(bodyu.ptr, val); | ||
835 | } | ||
836 | |||
837 | // ===================================================================================== | ||
838 | // btRigidBody entries | ||
839 | public override void ApplyGravity(BulletBody obj) | ||
840 | { | ||
841 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
842 | BSAPICPP.ApplyGravity2(bodyu.ptr); | ||
843 | } | ||
844 | |||
845 | public override void SetGravity(BulletBody obj, Vector3 val) | ||
846 | { | ||
847 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
848 | BSAPICPP.SetGravity2(bodyu.ptr, val); | ||
849 | } | ||
850 | |||
851 | public override Vector3 GetGravity(BulletBody obj) | ||
852 | { | ||
853 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
854 | return BSAPICPP.GetGravity2(bodyu.ptr); | ||
855 | } | ||
856 | |||
857 | public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping) | ||
858 | { | ||
859 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
860 | BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping); | ||
861 | } | ||
862 | |||
863 | public override void SetLinearDamping(BulletBody obj, float lin_damping) | ||
864 | { | ||
865 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
866 | BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping); | ||
867 | } | ||
868 | |||
869 | public override void SetAngularDamping(BulletBody obj, float ang_damping) | ||
870 | { | ||
871 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
872 | BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping); | ||
873 | } | ||
874 | |||
875 | public override float GetLinearDamping(BulletBody obj) | ||
876 | { | ||
877 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
878 | return BSAPICPP.GetLinearDamping2(bodyu.ptr); | ||
879 | } | ||
880 | |||
881 | public override float GetAngularDamping(BulletBody obj) | ||
882 | { | ||
883 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
884 | return BSAPICPP.GetAngularDamping2(bodyu.ptr); | ||
885 | } | ||
886 | |||
887 | public override float GetLinearSleepingThreshold(BulletBody obj) | ||
888 | { | ||
889 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
890 | return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr); | ||
891 | } | ||
892 | |||
893 | public override void ApplyDamping(BulletBody obj, float timeStep) | ||
894 | { | ||
895 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
896 | BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep); | ||
897 | } | ||
898 | |||
899 | public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia) | ||
900 | { | ||
901 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
902 | BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia); | ||
903 | } | ||
904 | |||
905 | public override Vector3 GetLinearFactor(BulletBody obj) | ||
906 | { | ||
907 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
908 | return BSAPICPP.GetLinearFactor2(bodyu.ptr); | ||
909 | } | ||
910 | |||
911 | public override void SetLinearFactor(BulletBody obj, Vector3 factor) | ||
912 | { | ||
913 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
914 | BSAPICPP.SetLinearFactor2(bodyu.ptr, factor); | ||
915 | } | ||
916 | |||
917 | public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) | ||
918 | { | ||
919 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
920 | BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot); | ||
921 | } | ||
922 | |||
923 | // Add a force to the object as if its mass is one. | ||
924 | // Deep down in Bullet: m_totalForce += force*m_linearFactor; | ||
925 | public override void ApplyCentralForce(BulletBody obj, Vector3 force) | ||
926 | { | ||
927 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
928 | BSAPICPP.ApplyCentralForce2(bodyu.ptr, force); | ||
929 | } | ||
930 | |||
931 | // Set the force being applied to the object as if its mass is one. | ||
932 | public override void SetObjectForce(BulletBody obj, Vector3 force) | ||
933 | { | ||
934 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
935 | BSAPICPP.SetObjectForce2(bodyu.ptr, force); | ||
936 | } | ||
937 | |||
938 | public override Vector3 GetTotalForce(BulletBody obj) | ||
939 | { | ||
940 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
941 | return BSAPICPP.GetTotalForce2(bodyu.ptr); | ||
942 | } | ||
943 | |||
944 | public override Vector3 GetTotalTorque(BulletBody obj) | ||
945 | { | ||
946 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
947 | return BSAPICPP.GetTotalTorque2(bodyu.ptr); | ||
948 | } | ||
949 | |||
950 | public override Vector3 GetInvInertiaDiagLocal(BulletBody obj) | ||
951 | { | ||
952 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
953 | return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr); | ||
954 | } | ||
955 | |||
956 | public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert) | ||
957 | { | ||
958 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
959 | BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert); | ||
960 | } | ||
961 | |||
962 | public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold) | ||
963 | { | ||
964 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
965 | BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold); | ||
966 | } | ||
967 | |||
968 | // Deep down in Bullet: m_totalTorque += torque*m_angularFactor; | ||
969 | public override void ApplyTorque(BulletBody obj, Vector3 torque) | ||
970 | { | ||
971 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
972 | BSAPICPP.ApplyTorque2(bodyu.ptr, torque); | ||
973 | } | ||
974 | |||
975 | // Apply force at the given point. Will add torque to the object. | ||
976 | // Deep down in Bullet: applyCentralForce(force); | ||
977 | // applyTorque(rel_pos.cross(force*m_linearFactor)); | ||
978 | public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos) | ||
979 | { | ||
980 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
981 | BSAPICPP.ApplyForce2(bodyu.ptr, force, pos); | ||
982 | } | ||
983 | |||
984 | // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. | ||
985 | // Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass; | ||
986 | public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp) | ||
987 | { | ||
988 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
989 | BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp); | ||
990 | } | ||
991 | |||
992 | // Apply impulse to the object's torque. Force is scaled by object's mass. | ||
993 | // Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor; | ||
994 | public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp) | ||
995 | { | ||
996 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
997 | BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp); | ||
998 | } | ||
999 | |||
1000 | // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. | ||
1001 | // Deep down in Bullet: applyCentralImpulse(impulse); | ||
1002 | // applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor)); | ||
1003 | public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos) | ||
1004 | { | ||
1005 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1006 | BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos); | ||
1007 | } | ||
1008 | |||
1009 | public override void ClearForces(BulletBody obj) | ||
1010 | { | ||
1011 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1012 | BSAPICPP.ClearForces2(bodyu.ptr); | ||
1013 | } | ||
1014 | |||
1015 | public override void ClearAllForces(BulletBody obj) | ||
1016 | { | ||
1017 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1018 | BSAPICPP.ClearAllForces2(bodyu.ptr); | ||
1019 | } | ||
1020 | |||
1021 | public override void UpdateInertiaTensor(BulletBody obj) | ||
1022 | { | ||
1023 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1024 | BSAPICPP.UpdateInertiaTensor2(bodyu.ptr); | ||
1025 | } | ||
1026 | |||
1027 | public override Vector3 GetLinearVelocity(BulletBody obj) | ||
1028 | { | ||
1029 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1030 | return BSAPICPP.GetLinearVelocity2(bodyu.ptr); | ||
1031 | } | ||
1032 | |||
1033 | public override Vector3 GetAngularVelocity(BulletBody obj) | ||
1034 | { | ||
1035 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1036 | return BSAPICPP.GetAngularVelocity2(bodyu.ptr); | ||
1037 | } | ||
1038 | |||
1039 | public override void SetLinearVelocity(BulletBody obj, Vector3 vel) | ||
1040 | { | ||
1041 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1042 | BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel); | ||
1043 | } | ||
1044 | |||
1045 | public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity) | ||
1046 | { | ||
1047 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1048 | BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity); | ||
1049 | } | ||
1050 | |||
1051 | public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos) | ||
1052 | { | ||
1053 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1054 | return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos); | ||
1055 | } | ||
1056 | |||
1057 | public override void Translate(BulletBody obj, Vector3 trans) | ||
1058 | { | ||
1059 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1060 | BSAPICPP.Translate2(bodyu.ptr, trans); | ||
1061 | } | ||
1062 | |||
1063 | public override void UpdateDeactivation(BulletBody obj, float timeStep) | ||
1064 | { | ||
1065 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1066 | BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep); | ||
1067 | } | ||
1068 | |||
1069 | public override bool WantsSleeping(BulletBody obj) | ||
1070 | { | ||
1071 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1072 | return BSAPICPP.WantsSleeping2(bodyu.ptr); | ||
1073 | } | ||
1074 | |||
1075 | public override void SetAngularFactor(BulletBody obj, float factor) | ||
1076 | { | ||
1077 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1078 | BSAPICPP.SetAngularFactor2(bodyu.ptr, factor); | ||
1079 | } | ||
1080 | |||
1081 | public override void SetAngularFactorV(BulletBody obj, Vector3 factor) | ||
1082 | { | ||
1083 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1084 | BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor); | ||
1085 | } | ||
1086 | |||
1087 | public override Vector3 GetAngularFactor(BulletBody obj) | ||
1088 | { | ||
1089 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1090 | return BSAPICPP.GetAngularFactor2(bodyu.ptr); | ||
1091 | } | ||
1092 | |||
1093 | public override bool IsInWorld(BulletWorld world, BulletBody obj) | ||
1094 | { | ||
1095 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1096 | return BSAPICPP.IsInWorld2(bodyu.ptr); | ||
1097 | } | ||
1098 | |||
1099 | public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain) | ||
1100 | { | ||
1101 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1102 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
1103 | BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr); | ||
1104 | } | ||
1105 | |||
1106 | public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain) | ||
1107 | { | ||
1108 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1109 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
1110 | BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr); | ||
1111 | } | ||
1112 | |||
1113 | public override BulletConstraint GetConstraintRef(BulletBody obj, int index) | ||
1114 | { | ||
1115 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1116 | return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index)); | ||
1117 | } | ||
1118 | |||
1119 | public override int GetNumConstraintRefs(BulletBody obj) | ||
1120 | { | ||
1121 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | ||
1122 | return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr); | ||
1123 | } | ||
1124 | |||
1125 | public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask) | ||
1126 | { | ||
1127 | BulletBodyUnman bodyu = body as BulletBodyUnman; | ||
1128 | return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask); | ||
1129 | } | ||
1130 | |||
1131 | // ===================================================================================== | ||
1132 | // btCollisionShape entries | ||
1133 | |||
1134 | public override float GetAngularMotionDisc(BulletShape shape) | ||
1135 | { | ||
1136 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1137 | return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr); | ||
1138 | } | ||
1139 | |||
1140 | public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor) | ||
1141 | { | ||
1142 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1143 | return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor); | ||
1144 | } | ||
1145 | |||
1146 | public override bool IsPolyhedral(BulletShape shape) | ||
1147 | { | ||
1148 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1149 | return BSAPICPP.IsPolyhedral2(shapeu.ptr); | ||
1150 | } | ||
1151 | |||
1152 | public override bool IsConvex2d(BulletShape shape) | ||
1153 | { | ||
1154 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1155 | return BSAPICPP.IsConvex2d2(shapeu.ptr); | ||
1156 | } | ||
1157 | |||
1158 | public override bool IsConvex(BulletShape shape) | ||
1159 | { | ||
1160 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1161 | return BSAPICPP.IsConvex2(shapeu.ptr); | ||
1162 | } | ||
1163 | |||
1164 | public override bool IsNonMoving(BulletShape shape) | ||
1165 | { | ||
1166 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1167 | return BSAPICPP.IsNonMoving2(shapeu.ptr); | ||
1168 | } | ||
1169 | |||
1170 | public override bool IsConcave(BulletShape shape) | ||
1171 | { | ||
1172 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1173 | return BSAPICPP.IsConcave2(shapeu.ptr); | ||
1174 | } | ||
1175 | |||
1176 | public override bool IsCompound(BulletShape shape) | ||
1177 | { | ||
1178 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1179 | return BSAPICPP.IsCompound2(shapeu.ptr); | ||
1180 | } | ||
1181 | |||
1182 | public override bool IsSoftBody(BulletShape shape) | ||
1183 | { | ||
1184 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1185 | return BSAPICPP.IsSoftBody2(shapeu.ptr); | ||
1186 | } | ||
1187 | |||
1188 | public override bool IsInfinite(BulletShape shape) | ||
1189 | { | ||
1190 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1191 | return BSAPICPP.IsInfinite2(shapeu.ptr); | ||
1192 | } | ||
1193 | |||
1194 | public override void SetLocalScaling(BulletShape shape, Vector3 scale) | ||
1195 | { | ||
1196 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1197 | BSAPICPP.SetLocalScaling2(shapeu.ptr, scale); | ||
1198 | } | ||
1199 | |||
1200 | public override Vector3 GetLocalScaling(BulletShape shape) | ||
1201 | { | ||
1202 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1203 | return BSAPICPP.GetLocalScaling2(shapeu.ptr); | ||
1204 | } | ||
1205 | |||
1206 | public override Vector3 CalculateLocalInertia(BulletShape shape, float mass) | ||
1207 | { | ||
1208 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1209 | return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass); | ||
1210 | } | ||
1211 | |||
1212 | public override int GetShapeType(BulletShape shape) | ||
1213 | { | ||
1214 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1215 | return BSAPICPP.GetShapeType2(shapeu.ptr); | ||
1216 | } | ||
1217 | |||
1218 | public override void SetMargin(BulletShape shape, float val) | ||
1219 | { | ||
1220 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1221 | BSAPICPP.SetMargin2(shapeu.ptr, val); | ||
1222 | } | ||
1223 | |||
1224 | public override float GetMargin(BulletShape shape) | ||
1225 | { | ||
1226 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | ||
1227 | return BSAPICPP.GetMargin2(shapeu.ptr); | ||
1228 | } | ||
1229 | |||
1230 | // ===================================================================================== | ||
1231 | // Debugging | ||
1232 | public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject) | ||
1233 | { | ||
1234 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1235 | BulletBodyUnman bodyu = collisionObject as BulletBodyUnman; | ||
1236 | BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr); | ||
1237 | } | ||
1238 | |||
1239 | public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape) | ||
1240 | { | ||
1241 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1242 | BulletShapeUnman shapeu = collisionShape as BulletShapeUnman; | ||
1243 | BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr); | ||
1244 | } | ||
1245 | |||
1246 | public override void DumpConstraint(BulletWorld world, BulletConstraint constrain) | ||
1247 | { | ||
1248 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1249 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | ||
1250 | BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr); | ||
1251 | } | ||
1252 | |||
1253 | public override void DumpActivationInfo(BulletWorld world) | ||
1254 | { | ||
1255 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1256 | BSAPICPP.DumpActivationInfo2(worldu.ptr); | ||
1257 | } | ||
1258 | |||
1259 | public override void DumpAllInfo(BulletWorld world) | ||
1260 | { | ||
1261 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1262 | BSAPICPP.DumpAllInfo2(worldu.ptr); | ||
1263 | } | ||
1264 | |||
1265 | public override void DumpPhysicsStatistics(BulletWorld world) | ||
1266 | { | ||
1267 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1268 | BSAPICPP.DumpPhysicsStatistics2(worldu.ptr); | ||
1269 | } | ||
1270 | public override void ResetBroadphasePool(BulletWorld world) | ||
1271 | { | ||
1272 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1273 | BSAPICPP.ResetBroadphasePool(worldu.ptr); | ||
1274 | } | ||
1275 | public override void ResetConstraintSolver(BulletWorld world) | ||
1276 | { | ||
1277 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1278 | BSAPICPP.ResetConstraintSolver(worldu.ptr); | ||
1279 | } | ||
1280 | |||
1281 | // ===================================================================================== | ||
1282 | // ===================================================================================== | ||
1283 | // ===================================================================================== | ||
1284 | // ===================================================================================== | ||
1285 | // ===================================================================================== | ||
1286 | // The actual interface to the unmanaged code | ||
1287 | static class BSAPICPP | ||
1288 | { | ||
1289 | // =============================================================================== | ||
1290 | // Link back to the managed code for outputting log messages | ||
1291 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
1292 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); | ||
1293 | |||
1294 | // =============================================================================== | ||
1295 | // Initialization and simulation | ||
1296 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1297 | public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, | ||
1298 | int maxCollisions, IntPtr collisionArray, | ||
1299 | int maxUpdates, IntPtr updateArray, | ||
1300 | DebugLogCallback logRoutine); | ||
1301 | |||
1302 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1303 | public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, | ||
1304 | out int updatedEntityCount, out int collidersCount); | ||
1305 | |||
1306 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1307 | public static extern void Shutdown2(IntPtr sim); | ||
1308 | |||
1309 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1310 | public static extern bool PushUpdate2(IntPtr obj); | ||
1311 | |||
1312 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1313 | public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); | ||
1314 | |||
1315 | // ===================================================================================== | ||
1316 | // Mesh, hull, shape and body creation helper routines | ||
1317 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1318 | public static extern IntPtr CreateMeshShape2(IntPtr world, | ||
1319 | int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | ||
1320 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | ||
1321 | |||
1322 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1323 | public static extern IntPtr CreateHullShape2(IntPtr world, | ||
1324 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); | ||
1325 | |||
1326 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1327 | public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape); | ||
1328 | |||
1329 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1330 | public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); | ||
1331 | |||
1332 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1333 | public static extern bool IsNativeShape2(IntPtr shape); | ||
1334 | |||
1335 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1336 | public static extern void SetShapeCollisionMargin2(IntPtr shape, float margin); | ||
1337 | |||
1338 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1339 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); | ||
1340 | |||
1341 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1342 | public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree); | ||
1343 | |||
1344 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1345 | public static extern int GetNumberOfCompoundChildren2(IntPtr cShape); | ||
1346 | |||
1347 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1348 | public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot); | ||
1349 | |||
1350 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1351 | public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); | ||
1352 | |||
1353 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1354 | public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); | ||
1355 | |||
1356 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1357 | public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); | ||
1358 | |||
1359 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1360 | public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape); | ||
1361 | |||
1362 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1363 | public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id); | ||
1364 | |||
1365 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1366 | public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape); | ||
1367 | |||
1368 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1369 | public static extern int GetBodyType2(IntPtr obj); | ||
1370 | |||
1371 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1372 | public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
1373 | |||
1374 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1375 | public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
1376 | |||
1377 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1378 | public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
1379 | |||
1380 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1381 | public static extern void DestroyObject2(IntPtr sim, IntPtr obj); | ||
1382 | |||
1383 | // ===================================================================================== | ||
1384 | // Terrain creation and helper routines | ||
1385 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1386 | public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); | ||
1387 | |||
1388 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1389 | public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, | ||
1390 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, | ||
1391 | float scaleFactor, float collisionMargin); | ||
1392 | |||
1393 | // ===================================================================================== | ||
1394 | // Constraint creation and helper routines | ||
1395 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1396 | public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1397 | Vector3 frame1loc, Quaternion frame1rot, | ||
1398 | Vector3 frame2loc, Quaternion frame2rot, | ||
1399 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1400 | |||
1401 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1402 | public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1403 | Vector3 joinPoint, | ||
1404 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1405 | |||
1406 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1407 | public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1408 | Vector3 pivotinA, Vector3 pivotinB, | ||
1409 | Vector3 axisInA, Vector3 axisInB, | ||
1410 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1411 | |||
1412 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1413 | public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); | ||
1414 | |||
1415 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1416 | public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); | ||
1417 | |||
1418 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1419 | public static extern bool SetFrames2(IntPtr constrain, | ||
1420 | Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); | ||
1421 | |||
1422 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1423 | public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi); | ||
1424 | |||
1425 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1426 | public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi); | ||
1427 | |||
1428 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1429 | public static extern bool UseFrameOffset2(IntPtr constrain, float enable); | ||
1430 | |||
1431 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1432 | public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce); | ||
1433 | |||
1434 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1435 | public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); | ||
1436 | |||
1437 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1438 | public static extern bool CalculateTransforms2(IntPtr constrain); | ||
1439 | |||
1440 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1441 | public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); | ||
1442 | |||
1443 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1444 | public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); | ||
1445 | |||
1446 | // ===================================================================================== | ||
1447 | // btCollisionWorld entries | ||
1448 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1449 | public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj); | ||
1450 | |||
1451 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1452 | public static extern void UpdateAabbs2(IntPtr world); | ||
1453 | |||
1454 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1455 | public static extern bool GetForceUpdateAllAabbs2(IntPtr world); | ||
1456 | |||
1457 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1458 | public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force); | ||
1459 | |||
1460 | // ===================================================================================== | ||
1461 | // btDynamicsWorld entries | ||
1462 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1463 | public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj); | ||
1464 | |||
1465 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1466 | public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); | ||
1467 | |||
1468 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1469 | public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); | ||
1470 | |||
1471 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1472 | public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain); | ||
1473 | // ===================================================================================== | ||
1474 | // btCollisionObject entries | ||
1475 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1476 | public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain); | ||
1477 | |||
1478 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1479 | public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict); | ||
1480 | |||
1481 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1482 | public static extern bool HasAnisotripicFriction2(IntPtr constrain); | ||
1483 | |||
1484 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1485 | public static extern void SetContactProcessingThreshold2(IntPtr obj, float val); | ||
1486 | |||
1487 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1488 | public static extern float GetContactProcessingThreshold2(IntPtr obj); | ||
1489 | |||
1490 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1491 | public static extern bool IsStaticObject2(IntPtr obj); | ||
1492 | |||
1493 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1494 | public static extern bool IsKinematicObject2(IntPtr obj); | ||
1495 | |||
1496 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1497 | public static extern bool IsStaticOrKinematicObject2(IntPtr obj); | ||
1498 | |||
1499 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1500 | public static extern bool HasContactResponse2(IntPtr obj); | ||
1501 | |||
1502 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1503 | public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape); | ||
1504 | |||
1505 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1506 | public static extern IntPtr GetCollisionShape2(IntPtr obj); | ||
1507 | |||
1508 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1509 | public static extern int GetActivationState2(IntPtr obj); | ||
1510 | |||
1511 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1512 | public static extern void SetActivationState2(IntPtr obj, int state); | ||
1513 | |||
1514 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1515 | public static extern void SetDeactivationTime2(IntPtr obj, float dtime); | ||
1516 | |||
1517 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1518 | public static extern float GetDeactivationTime2(IntPtr obj); | ||
1519 | |||
1520 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1521 | public static extern void ForceActivationState2(IntPtr obj, ActivationState state); | ||
1522 | |||
1523 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1524 | public static extern void Activate2(IntPtr obj, bool forceActivation); | ||
1525 | |||
1526 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1527 | public static extern bool IsActive2(IntPtr obj); | ||
1528 | |||
1529 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1530 | public static extern void SetRestitution2(IntPtr obj, float val); | ||
1531 | |||
1532 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1533 | public static extern float GetRestitution2(IntPtr obj); | ||
1534 | |||
1535 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1536 | public static extern void SetFriction2(IntPtr obj, float val); | ||
1537 | |||
1538 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1539 | public static extern float GetFriction2(IntPtr obj); | ||
1540 | |||
1541 | /* Haven't defined the type 'Transform' | ||
1542 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1543 | public static extern Transform GetWorldTransform2(IntPtr obj); | ||
1544 | |||
1545 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1546 | public static extern void setWorldTransform2(IntPtr obj, Transform trans); | ||
1547 | */ | ||
1548 | |||
1549 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1550 | public static extern Vector3 GetPosition2(IntPtr obj); | ||
1551 | |||
1552 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1553 | public static extern Quaternion GetOrientation2(IntPtr obj); | ||
1554 | |||
1555 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1556 | public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); | ||
1557 | |||
1558 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1559 | public static extern IntPtr GetBroadphaseHandle2(IntPtr obj); | ||
1560 | |||
1561 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1562 | public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle); | ||
1563 | |||
1564 | /* | ||
1565 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1566 | public static extern Transform GetInterpolationWorldTransform2(IntPtr obj); | ||
1567 | |||
1568 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1569 | public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans); | ||
1570 | */ | ||
1571 | |||
1572 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1573 | public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel); | ||
1574 | |||
1575 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1576 | public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel); | ||
1577 | |||
1578 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1579 | public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel); | ||
1580 | |||
1581 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1582 | public static extern float GetHitFraction2(IntPtr obj); | ||
1583 | |||
1584 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1585 | public static extern void SetHitFraction2(IntPtr obj, float val); | ||
1586 | |||
1587 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1588 | public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); | ||
1589 | |||
1590 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1591 | public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
1592 | |||
1593 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1594 | public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
1595 | |||
1596 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1597 | public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
1598 | |||
1599 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1600 | public static extern float GetCcdMotionThreshold2(IntPtr obj); | ||
1601 | |||
1602 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1603 | public static extern void SetCcdMotionThreshold2(IntPtr obj, float val); | ||
1604 | |||
1605 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1606 | public static extern float GetCcdSweptSphereRadius2(IntPtr obj); | ||
1607 | |||
1608 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1609 | public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val); | ||
1610 | |||
1611 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1612 | public static extern IntPtr GetUserPointer2(IntPtr obj); | ||
1613 | |||
1614 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1615 | public static extern void SetUserPointer2(IntPtr obj, IntPtr val); | ||
1616 | |||
1617 | // ===================================================================================== | ||
1618 | // btRigidBody entries | ||
1619 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1620 | public static extern void ApplyGravity2(IntPtr obj); | ||
1621 | |||
1622 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1623 | public static extern void SetGravity2(IntPtr obj, Vector3 val); | ||
1624 | |||
1625 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1626 | public static extern Vector3 GetGravity2(IntPtr obj); | ||
1627 | |||
1628 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1629 | public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping); | ||
1630 | |||
1631 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1632 | public static extern void SetLinearDamping2(IntPtr obj, float lin_damping); | ||
1633 | |||
1634 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1635 | public static extern void SetAngularDamping2(IntPtr obj, float ang_damping); | ||
1636 | |||
1637 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1638 | public static extern float GetLinearDamping2(IntPtr obj); | ||
1639 | |||
1640 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1641 | public static extern float GetAngularDamping2(IntPtr obj); | ||
1642 | |||
1643 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1644 | public static extern float GetLinearSleepingThreshold2(IntPtr obj); | ||
1645 | |||
1646 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1647 | public static extern float GetAngularSleepingThreshold2(IntPtr obj); | ||
1648 | |||
1649 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1650 | public static extern void ApplyDamping2(IntPtr obj, float timeStep); | ||
1651 | |||
1652 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1653 | public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia); | ||
1654 | |||
1655 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1656 | public static extern Vector3 GetLinearFactor2(IntPtr obj); | ||
1657 | |||
1658 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1659 | public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor); | ||
1660 | |||
1661 | /* | ||
1662 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1663 | public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans); | ||
1664 | */ | ||
1665 | |||
1666 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1667 | public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot); | ||
1668 | |||
1669 | // Add a force to the object as if its mass is one. | ||
1670 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1671 | public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force); | ||
1672 | |||
1673 | // Set the force being applied to the object as if its mass is one. | ||
1674 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1675 | public static extern void SetObjectForce2(IntPtr obj, Vector3 force); | ||
1676 | |||
1677 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1678 | public static extern Vector3 GetTotalForce2(IntPtr obj); | ||
1679 | |||
1680 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1681 | public static extern Vector3 GetTotalTorque2(IntPtr obj); | ||
1682 | |||
1683 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1684 | public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj); | ||
1685 | |||
1686 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1687 | public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert); | ||
1688 | |||
1689 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1690 | public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); | ||
1691 | |||
1692 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1693 | public static extern void ApplyTorque2(IntPtr obj, Vector3 torque); | ||
1694 | |||
1695 | // Apply force at the given point. Will add torque to the object. | ||
1696 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1697 | public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos); | ||
1698 | |||
1699 | // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. | ||
1700 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1701 | public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp); | ||
1702 | |||
1703 | // Apply impulse to the object's torque. Force is scaled by object's mass. | ||
1704 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1705 | public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp); | ||
1706 | |||
1707 | // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. | ||
1708 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1709 | public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos); | ||
1710 | |||
1711 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1712 | public static extern void ClearForces2(IntPtr obj); | ||
1713 | |||
1714 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1715 | public static extern void ClearAllForces2(IntPtr obj); | ||
1716 | |||
1717 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1718 | public static extern void UpdateInertiaTensor2(IntPtr obj); | ||
1719 | |||
1720 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1721 | public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj); | ||
1722 | |||
1723 | /* | ||
1724 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1725 | public static extern Transform GetCenterOfMassTransform2(IntPtr obj); | ||
1726 | */ | ||
1727 | |||
1728 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1729 | public static extern Vector3 GetLinearVelocity2(IntPtr obj); | ||
1730 | |||
1731 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1732 | public static extern Vector3 GetAngularVelocity2(IntPtr obj); | ||
1733 | |||
1734 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1735 | public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val); | ||
1736 | |||
1737 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1738 | public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); | ||
1739 | |||
1740 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1741 | public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos); | ||
1742 | |||
1743 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1744 | public static extern void Translate2(IntPtr obj, Vector3 trans); | ||
1745 | |||
1746 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1747 | public static extern void UpdateDeactivation2(IntPtr obj, float timeStep); | ||
1748 | |||
1749 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1750 | public static extern bool WantsSleeping2(IntPtr obj); | ||
1751 | |||
1752 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1753 | public static extern void SetAngularFactor2(IntPtr obj, float factor); | ||
1754 | |||
1755 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1756 | public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor); | ||
1757 | |||
1758 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1759 | public static extern Vector3 GetAngularFactor2(IntPtr obj); | ||
1760 | |||
1761 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1762 | public static extern bool IsInWorld2(IntPtr obj); | ||
1763 | |||
1764 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1765 | public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain); | ||
1766 | |||
1767 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1768 | public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain); | ||
1769 | |||
1770 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1771 | public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); | ||
1772 | |||
1773 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1774 | public static extern int GetNumConstraintRefs2(IntPtr obj); | ||
1775 | |||
1776 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1777 | public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask); | ||
1778 | |||
1779 | // ===================================================================================== | ||
1780 | // btCollisionShape entries | ||
1781 | |||
1782 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1783 | public static extern float GetAngularMotionDisc2(IntPtr shape); | ||
1784 | |||
1785 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1786 | public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor); | ||
1787 | |||
1788 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1789 | public static extern bool IsPolyhedral2(IntPtr shape); | ||
1790 | |||
1791 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1792 | public static extern bool IsConvex2d2(IntPtr shape); | ||
1793 | |||
1794 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1795 | public static extern bool IsConvex2(IntPtr shape); | ||
1796 | |||
1797 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1798 | public static extern bool IsNonMoving2(IntPtr shape); | ||
1799 | |||
1800 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1801 | public static extern bool IsConcave2(IntPtr shape); | ||
1802 | |||
1803 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1804 | public static extern bool IsCompound2(IntPtr shape); | ||
1805 | |||
1806 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1807 | public static extern bool IsSoftBody2(IntPtr shape); | ||
1808 | |||
1809 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1810 | public static extern bool IsInfinite2(IntPtr shape); | ||
1811 | |||
1812 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1813 | public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale); | ||
1814 | |||
1815 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1816 | public static extern Vector3 GetLocalScaling2(IntPtr shape); | ||
1817 | |||
1818 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1819 | public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass); | ||
1820 | |||
1821 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1822 | public static extern int GetShapeType2(IntPtr shape); | ||
1823 | |||
1824 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1825 | public static extern void SetMargin2(IntPtr shape, float val); | ||
1826 | |||
1827 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1828 | public static extern float GetMargin2(IntPtr shape); | ||
1829 | |||
1830 | // ===================================================================================== | ||
1831 | // Debugging | ||
1832 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1833 | public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); | ||
1834 | |||
1835 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1836 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); | ||
1837 | |||
1838 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1839 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | ||
1840 | |||
1841 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1842 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); | ||
1843 | |||
1844 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1845 | public static extern void DumpActivationInfo2(IntPtr sim); | ||
1846 | |||
1847 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1848 | public static extern void DumpAllInfo2(IntPtr sim); | ||
1849 | |||
1850 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1851 | public static extern void DumpPhysicsStatistics2(IntPtr sim); | ||
1852 | |||
1853 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1854 | public static extern void ResetBroadphasePool(IntPtr sim); | ||
1855 | |||
1856 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1857 | public static extern void ResetConstraintSolver(IntPtr sim); | ||
1858 | |||
1859 | } | ||
1860 | |||
1861 | } | ||
1862 | |||
1863 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs new file mode 100755 index 0000000..0c7f315 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs | |||
@@ -0,0 +1,1597 @@ | |||
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.Text; | ||
31 | |||
32 | using OpenSim.Framework; | ||
33 | |||
34 | using OpenMetaverse; | ||
35 | |||
36 | using BulletXNA; | ||
37 | using BulletXNA.LinearMath; | ||
38 | using BulletXNA.BulletCollision; | ||
39 | using BulletXNA.BulletDynamics; | ||
40 | using BulletXNA.BulletCollision.CollisionDispatch; | ||
41 | |||
42 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
43 | { | ||
44 | public sealed class BSAPIXNA : BSAPITemplate | ||
45 | { | ||
46 | private sealed class BulletWorldXNA : BulletWorld | ||
47 | { | ||
48 | public DiscreteDynamicsWorld world; | ||
49 | public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx) | ||
50 | : base(id, physScene) | ||
51 | { | ||
52 | world = xx; | ||
53 | } | ||
54 | } | ||
55 | |||
56 | private sealed class BulletBodyXNA : BulletBody | ||
57 | { | ||
58 | public CollisionObject body; | ||
59 | public RigidBody rigidBody { get { return RigidBody.Upcast(body); } } | ||
60 | |||
61 | public BulletBodyXNA(uint id, CollisionObject xx) | ||
62 | : base(id) | ||
63 | { | ||
64 | body = xx; | ||
65 | } | ||
66 | public override bool HasPhysicalBody | ||
67 | { | ||
68 | get { return body != null; } | ||
69 | } | ||
70 | public override void Clear() | ||
71 | { | ||
72 | body = null; | ||
73 | } | ||
74 | public override string AddrString | ||
75 | { | ||
76 | get { return "XNARigidBody"; } | ||
77 | } | ||
78 | } | ||
79 | |||
80 | private sealed class BulletShapeXNA : BulletShape | ||
81 | { | ||
82 | public CollisionShape shape; | ||
83 | public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) | ||
84 | : base() | ||
85 | { | ||
86 | shape = xx; | ||
87 | type = typ; | ||
88 | } | ||
89 | public override bool HasPhysicalShape | ||
90 | { | ||
91 | get { return shape != null; } | ||
92 | } | ||
93 | public override void Clear() | ||
94 | { | ||
95 | shape = null; | ||
96 | } | ||
97 | public override BulletShape Clone() | ||
98 | { | ||
99 | return new BulletShapeXNA(shape, type); | ||
100 | } | ||
101 | public override bool ReferenceSame(BulletShape other) | ||
102 | { | ||
103 | BulletShapeXNA otheru = other as BulletShapeXNA; | ||
104 | return (otheru != null) && (this.shape == otheru.shape); | ||
105 | |||
106 | } | ||
107 | public override string AddrString | ||
108 | { | ||
109 | get { return "XNACollisionShape"; } | ||
110 | } | ||
111 | } | ||
112 | private sealed class BulletConstraintXNA : BulletConstraint | ||
113 | { | ||
114 | public TypedConstraint constrain; | ||
115 | public BulletConstraintXNA(TypedConstraint xx) : base() | ||
116 | { | ||
117 | constrain = xx; | ||
118 | } | ||
119 | |||
120 | public override void Clear() | ||
121 | { | ||
122 | constrain = null; | ||
123 | } | ||
124 | public override bool HasPhysicalConstraint { get { return constrain != null; } } | ||
125 | |||
126 | // Used for log messages for a unique display of the memory/object allocated to this instance | ||
127 | public override string AddrString | ||
128 | { | ||
129 | get { return "XNAConstraint"; } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | private static int m_collisionsThisFrame; | ||
134 | private BSScene PhysicsScene { get; set; } | ||
135 | |||
136 | public override string BulletEngineName { get { return "BulletXNA"; } } | ||
137 | public override string BulletEngineVersion { get; protected set; } | ||
138 | |||
139 | public BSAPIXNA(string paramName, BSScene physScene) | ||
140 | { | ||
141 | PhysicsScene = physScene; | ||
142 | } | ||
143 | |||
144 | /// <summary> | ||
145 | /// | ||
146 | /// </summary> | ||
147 | /// <param name="p"></param> | ||
148 | /// <param name="p_2"></param> | ||
149 | public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody) | ||
150 | { | ||
151 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
152 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
153 | world.RemoveRigidBody(body); | ||
154 | return true; | ||
155 | } | ||
156 | |||
157 | public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) | ||
158 | { | ||
159 | /* TODO */ | ||
160 | return false; | ||
161 | } | ||
162 | |||
163 | public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain) | ||
164 | { | ||
165 | /* TODO */ | ||
166 | return false; | ||
167 | } | ||
168 | |||
169 | public override void SetRestitution(BulletBody pBody, float pRestitution) | ||
170 | { | ||
171 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
172 | body.SetRestitution(pRestitution); | ||
173 | } | ||
174 | |||
175 | public override int GetShapeType(BulletShape pShape) | ||
176 | { | ||
177 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
178 | return (int)shape.GetShapeType(); | ||
179 | } | ||
180 | public override void SetMargin(BulletShape pShape, float pMargin) | ||
181 | { | ||
182 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
183 | shape.SetMargin(pMargin); | ||
184 | } | ||
185 | |||
186 | public override float GetMargin(BulletShape pShape) | ||
187 | { | ||
188 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
189 | return shape.GetMargin(); | ||
190 | } | ||
191 | |||
192 | public override void SetLocalScaling(BulletShape pShape, Vector3 pScale) | ||
193 | { | ||
194 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
195 | IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); | ||
196 | shape.SetLocalScaling(ref vec); | ||
197 | |||
198 | } | ||
199 | |||
200 | public override void SetContactProcessingThreshold(BulletBody pBody, float contactprocessingthreshold) | ||
201 | { | ||
202 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
203 | body.SetContactProcessingThreshold(contactprocessingthreshold); | ||
204 | } | ||
205 | |||
206 | public override void SetCcdMotionThreshold(BulletBody pBody, float pccdMotionThreashold) | ||
207 | { | ||
208 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
209 | body.SetCcdMotionThreshold(pccdMotionThreashold); | ||
210 | } | ||
211 | |||
212 | public override void SetCcdSweptSphereRadius(BulletBody pBody, float pCcdSweptSphereRadius) | ||
213 | { | ||
214 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
215 | body.SetCcdSweptSphereRadius(pCcdSweptSphereRadius); | ||
216 | } | ||
217 | |||
218 | public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor) | ||
219 | { | ||
220 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
221 | body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z)); | ||
222 | } | ||
223 | |||
224 | public override CollisionFlags AddToCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags) | ||
225 | { | ||
226 | CollisionObject body = ((BulletBodyXNA)pBody).body; | ||
227 | CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags(); | ||
228 | existingcollisionFlags |= pcollisionFlags; | ||
229 | body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); | ||
230 | return (CollisionFlags) (uint) existingcollisionFlags; | ||
231 | } | ||
232 | |||
233 | public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody) | ||
234 | { | ||
235 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
236 | CollisionObject cbody = ((BulletBodyXNA)pBody).body; | ||
237 | RigidBody rbody = cbody as RigidBody; | ||
238 | |||
239 | // Bullet resets several variables when an object is added to the world. In particular, | ||
240 | // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic | ||
241 | // type. Of course, the collision flags in the broadphase proxy are initialized to default. | ||
242 | IndexedMatrix origPos = cbody.GetWorldTransform(); | ||
243 | if (rbody != null) | ||
244 | { | ||
245 | IndexedVector3 origGrav = rbody.GetGravity(); | ||
246 | world.AddRigidBody(rbody); | ||
247 | rbody.SetGravity(origGrav); | ||
248 | } | ||
249 | else | ||
250 | { | ||
251 | world.AddCollisionObject(rbody); | ||
252 | } | ||
253 | cbody.SetWorldTransform(origPos); | ||
254 | |||
255 | pBody.ApplyCollisionMask(pWorld.physicsScene); | ||
256 | |||
257 | //if (body.GetBroadphaseHandle() != null) | ||
258 | // world.UpdateSingleAabb(body); | ||
259 | return true; | ||
260 | } | ||
261 | |||
262 | public override void ForceActivationState(BulletBody pBody, ActivationState pActivationState) | ||
263 | { | ||
264 | CollisionObject body = ((BulletBodyXNA)pBody).body; | ||
265 | body.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState); | ||
266 | } | ||
267 | |||
268 | public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pBody) | ||
269 | { | ||
270 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
271 | CollisionObject body = ((BulletBodyXNA)pBody).body; | ||
272 | world.UpdateSingleAabb(body); | ||
273 | } | ||
274 | |||
275 | public override void UpdateAabbs(BulletWorld world) { /* TODO */ } | ||
276 | public override bool GetForceUpdateAllAabbs(BulletWorld world) { /* TODO */ return false; } | ||
277 | public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) { /* TODO */ } | ||
278 | |||
279 | public override bool SetCollisionGroupMask(BulletBody pBody, uint pGroup, uint pMask) | ||
280 | { | ||
281 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
282 | body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; | ||
283 | body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; | ||
284 | if ((uint) body.GetBroadphaseHandle().m_collisionFilterGroup == 0) | ||
285 | return false; | ||
286 | return true; | ||
287 | } | ||
288 | |||
289 | public override void ClearAllForces(BulletBody pBody) | ||
290 | { | ||
291 | CollisionObject body = ((BulletBodyXNA)pBody).body; | ||
292 | IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0); | ||
293 | body.SetInterpolationLinearVelocity(ref zeroVector); | ||
294 | body.SetInterpolationAngularVelocity(ref zeroVector); | ||
295 | IndexedMatrix bodytransform = body.GetWorldTransform(); | ||
296 | |||
297 | body.SetInterpolationWorldTransform(ref bodytransform); | ||
298 | |||
299 | if (body is RigidBody) | ||
300 | { | ||
301 | RigidBody rigidbody = body as RigidBody; | ||
302 | rigidbody.SetLinearVelocity(zeroVector); | ||
303 | rigidbody.SetAngularVelocity(zeroVector); | ||
304 | rigidbody.ClearForces(); | ||
305 | } | ||
306 | } | ||
307 | |||
308 | public override void SetInterpolationAngularVelocity(BulletBody pBody, Vector3 pVector3) | ||
309 | { | ||
310 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
311 | IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); | ||
312 | body.SetInterpolationAngularVelocity(ref vec); | ||
313 | } | ||
314 | |||
315 | public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3) | ||
316 | { | ||
317 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
318 | IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); | ||
319 | body.SetAngularVelocity(ref vec); | ||
320 | } | ||
321 | public override Vector3 GetTotalForce(BulletBody pBody) | ||
322 | { | ||
323 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
324 | IndexedVector3 iv3 = body.GetTotalForce(); | ||
325 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
326 | } | ||
327 | public override Vector3 GetTotalTorque(BulletBody pBody) | ||
328 | { | ||
329 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
330 | IndexedVector3 iv3 = body.GetTotalTorque(); | ||
331 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
332 | } | ||
333 | public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody) | ||
334 | { | ||
335 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
336 | IndexedVector3 iv3 = body.GetInvInertiaDiagLocal(); | ||
337 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
338 | } | ||
339 | public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert) | ||
340 | { | ||
341 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
342 | IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z); | ||
343 | body.SetInvInertiaDiagLocal(ref iv3); | ||
344 | } | ||
345 | public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos) | ||
346 | { | ||
347 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
348 | IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z); | ||
349 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); | ||
350 | body.ApplyForce(ref forceiv3, ref posiv3); | ||
351 | } | ||
352 | public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos) | ||
353 | { | ||
354 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
355 | IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z); | ||
356 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); | ||
357 | body.ApplyImpulse(ref impiv3, ref posiv3); | ||
358 | } | ||
359 | |||
360 | public override void ClearForces(BulletBody pBody) | ||
361 | { | ||
362 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
363 | body.ClearForces(); | ||
364 | } | ||
365 | |||
366 | public override void SetTranslation(BulletBody pBody, Vector3 _position, Quaternion _orientation) | ||
367 | { | ||
368 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
369 | IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z); | ||
370 | IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z, | ||
371 | _orientation.W); | ||
372 | IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); | ||
373 | mat._origin = vposition; | ||
374 | body.SetWorldTransform(mat); | ||
375 | |||
376 | } | ||
377 | |||
378 | public override Vector3 GetPosition(BulletBody pBody) | ||
379 | { | ||
380 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
381 | IndexedVector3 pos = body.GetInterpolationWorldTransform()._origin; | ||
382 | return new Vector3(pos.X, pos.Y, pos.Z); | ||
383 | } | ||
384 | |||
385 | public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass) | ||
386 | { | ||
387 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
388 | IndexedVector3 inertia = IndexedVector3.Zero; | ||
389 | shape.CalculateLocalInertia(pphysMass, out inertia); | ||
390 | return new Vector3(inertia.X, inertia.Y, inertia.Z); | ||
391 | } | ||
392 | |||
393 | public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia) | ||
394 | { | ||
395 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
396 | IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z); | ||
397 | body.SetMassProps(pphysMass, inertia); | ||
398 | } | ||
399 | |||
400 | |||
401 | public override void SetObjectForce(BulletBody pBody, Vector3 _force) | ||
402 | { | ||
403 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
404 | IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z); | ||
405 | body.SetTotalForce(ref force); | ||
406 | } | ||
407 | |||
408 | public override void SetFriction(BulletBody pBody, float _currentFriction) | ||
409 | { | ||
410 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
411 | body.SetFriction(_currentFriction); | ||
412 | } | ||
413 | |||
414 | public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity) | ||
415 | { | ||
416 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
417 | IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z); | ||
418 | body.SetLinearVelocity(velocity); | ||
419 | } | ||
420 | |||
421 | public override void Activate(BulletBody pBody, bool pforceactivation) | ||
422 | { | ||
423 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
424 | body.Activate(pforceactivation); | ||
425 | |||
426 | } | ||
427 | |||
428 | public override Quaternion GetOrientation(BulletBody pBody) | ||
429 | { | ||
430 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
431 | IndexedQuaternion mat = body.GetInterpolationWorldTransform().GetRotation(); | ||
432 | return new Quaternion(mat.X, mat.Y, mat.Z, mat.W); | ||
433 | } | ||
434 | |||
435 | public override CollisionFlags RemoveFromCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags) | ||
436 | { | ||
437 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
438 | CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags(); | ||
439 | existingcollisionFlags &= ~pcollisionFlags; | ||
440 | body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); | ||
441 | return (CollisionFlags)(uint)existingcollisionFlags; | ||
442 | } | ||
443 | |||
444 | public override float GetCcdMotionThreshold(BulletBody obj) { /* TODO */ return 0f; } | ||
445 | |||
446 | public override float GetCcdSweptSphereRadius(BulletBody obj) { /* TODO */ return 0f; } | ||
447 | |||
448 | public override IntPtr GetUserPointer(BulletBody obj) { /* TODO */ return IntPtr.Zero; } | ||
449 | |||
450 | public override void SetUserPointer(BulletBody obj, IntPtr val) { /* TODO */ } | ||
451 | |||
452 | public override void SetGravity(BulletBody pBody, Vector3 pGravity) | ||
453 | { | ||
454 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
455 | IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z); | ||
456 | body.SetGravity(gravity); | ||
457 | } | ||
458 | |||
459 | public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint) | ||
460 | { | ||
461 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
462 | TypedConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain; | ||
463 | world.RemoveConstraint(constraint); | ||
464 | return true; | ||
465 | } | ||
466 | |||
467 | public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) | ||
468 | { | ||
469 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | ||
470 | IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); | ||
471 | IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); | ||
472 | constraint.SetLinearLowerLimit(lowlimit); | ||
473 | constraint.SetLinearUpperLimit(highlimit); | ||
474 | return true; | ||
475 | } | ||
476 | |||
477 | public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) | ||
478 | { | ||
479 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | ||
480 | IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); | ||
481 | IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); | ||
482 | constraint.SetAngularLowerLimit(lowlimit); | ||
483 | constraint.SetAngularUpperLimit(highlimit); | ||
484 | return true; | ||
485 | } | ||
486 | |||
487 | public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt) | ||
488 | { | ||
489 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | ||
490 | constraint.SetOverrideNumSolverIterations((int)cnt); | ||
491 | } | ||
492 | |||
493 | public override bool CalculateTransforms(BulletConstraint pConstraint) | ||
494 | { | ||
495 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | ||
496 | constraint.CalculateTransforms(); | ||
497 | return true; | ||
498 | } | ||
499 | |||
500 | public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2) | ||
501 | { | ||
502 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | ||
503 | constraint.SetEnabled((p_2 == 0) ? false : true); | ||
504 | } | ||
505 | |||
506 | |||
507 | //BulletSimAPI.Create6DofConstraint(m_world.ptr, m_body1.ptr, m_body2.ptr,frame1, frame1rot,frame2, frame2rot,useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
508 | public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
509 | |||
510 | { | ||
511 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
512 | RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody; | ||
513 | RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody; | ||
514 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
515 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
516 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
517 | frame1._origin = frame1v; | ||
518 | |||
519 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
520 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
521 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
522 | frame2._origin = frame1v; | ||
523 | |||
524 | Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, | ||
525 | puseLinearReferenceFrameA); | ||
526 | consttr.CalculateTransforms(); | ||
527 | world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); | ||
528 | |||
529 | return new BulletConstraintXNA(consttr); | ||
530 | } | ||
531 | |||
532 | |||
533 | /// <summary> | ||
534 | /// | ||
535 | /// </summary> | ||
536 | /// <param name="pWorld"></param> | ||
537 | /// <param name="pBody1"></param> | ||
538 | /// <param name="pBody2"></param> | ||
539 | /// <param name="pjoinPoint"></param> | ||
540 | /// <param name="puseLinearReferenceFrameA"></param> | ||
541 | /// <param name="pdisableCollisionsBetweenLinkedBodies"></param> | ||
542 | /// <returns></returns> | ||
543 | public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
544 | { | ||
545 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
546 | RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody; | ||
547 | RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody; | ||
548 | IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); | ||
549 | IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); | ||
550 | |||
551 | IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); | ||
552 | IndexedMatrix mat = IndexedMatrix.Identity; | ||
553 | mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); | ||
554 | frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint; | ||
555 | frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint; | ||
556 | |||
557 | Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); | ||
558 | consttr.CalculateTransforms(); | ||
559 | world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies); | ||
560 | |||
561 | return new BulletConstraintXNA(consttr); | ||
562 | } | ||
563 | //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); | ||
564 | public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot) | ||
565 | { | ||
566 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | ||
567 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
568 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
569 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
570 | frame1._origin = frame1v; | ||
571 | |||
572 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
573 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
574 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
575 | frame2._origin = frame1v; | ||
576 | constraint.SetFrames(ref frame1, ref frame2); | ||
577 | return true; | ||
578 | } | ||
579 | |||
580 | public override Vector3 GetLinearVelocity(BulletBody pBody) | ||
581 | { | ||
582 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
583 | IndexedVector3 iv3 = body.GetLinearVelocity(); | ||
584 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
585 | } | ||
586 | public override Vector3 GetAngularVelocity(BulletBody pBody) | ||
587 | { | ||
588 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
589 | IndexedVector3 iv3 = body.GetAngularVelocity(); | ||
590 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
591 | } | ||
592 | public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos) | ||
593 | { | ||
594 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
595 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); | ||
596 | IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3); | ||
597 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
598 | } | ||
599 | public override void Translate(BulletBody pBody, Vector3 trans) | ||
600 | { | ||
601 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
602 | } | ||
603 | public override void UpdateDeactivation(BulletBody pBody, float timeStep) | ||
604 | { | ||
605 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
606 | body.UpdateDeactivation(timeStep); | ||
607 | } | ||
608 | |||
609 | public override bool WantsSleeping(BulletBody pBody) | ||
610 | { | ||
611 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
612 | return body.WantsSleeping(); | ||
613 | } | ||
614 | |||
615 | public override void SetAngularFactor(BulletBody pBody, float factor) | ||
616 | { | ||
617 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
618 | body.SetAngularFactor(factor); | ||
619 | } | ||
620 | |||
621 | public override Vector3 GetAngularFactor(BulletBody pBody) | ||
622 | { | ||
623 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
624 | IndexedVector3 iv3 = body.GetAngularFactor(); | ||
625 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | ||
626 | } | ||
627 | |||
628 | public override bool IsInWorld(BulletWorld pWorld, BulletBody pBody) | ||
629 | { | ||
630 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
631 | CollisionObject body = ((BulletBodyXNA)pBody).body; | ||
632 | return world.IsInWorld(body); | ||
633 | } | ||
634 | |||
635 | public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstrain) | ||
636 | { | ||
637 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
638 | TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain; | ||
639 | body.AddConstraintRef(constrain); | ||
640 | } | ||
641 | |||
642 | public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstrain) | ||
643 | { | ||
644 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
645 | TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain; | ||
646 | body.RemoveConstraintRef(constrain); | ||
647 | } | ||
648 | |||
649 | public override BulletConstraint GetConstraintRef(BulletBody pBody, int index) | ||
650 | { | ||
651 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
652 | return new BulletConstraintXNA(body.GetConstraintRef(index)); | ||
653 | } | ||
654 | |||
655 | public override int GetNumConstraintRefs(BulletBody pBody) | ||
656 | { | ||
657 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
658 | return body.GetNumConstraintRefs(); | ||
659 | } | ||
660 | |||
661 | public override void SetInterpolationLinearVelocity(BulletBody pBody, Vector3 VehicleVelocity) | ||
662 | { | ||
663 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
664 | IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z); | ||
665 | body.SetInterpolationLinearVelocity(ref velocity); | ||
666 | } | ||
667 | |||
668 | public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff) | ||
669 | { | ||
670 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | ||
671 | constraint.SetUseFrameOffset((onOff == 0) ? false : true); | ||
672 | return true; | ||
673 | } | ||
674 | //SetBreakingImpulseThreshold(m_constraint.ptr, threshold); | ||
675 | public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold) | ||
676 | { | ||
677 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | ||
678 | constraint.SetBreakingImpulseThreshold(threshold); | ||
679 | return true; | ||
680 | } | ||
681 | //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping); | ||
682 | public override void SetAngularDamping(BulletBody pBody, float angularDamping) | ||
683 | { | ||
684 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
685 | float lineardamping = body.GetLinearDamping(); | ||
686 | body.SetDamping(lineardamping, angularDamping); | ||
687 | |||
688 | } | ||
689 | |||
690 | public override void UpdateInertiaTensor(BulletBody pBody) | ||
691 | { | ||
692 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
693 | body.UpdateInertiaTensor(); | ||
694 | } | ||
695 | |||
696 | public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape) | ||
697 | { | ||
698 | CompoundShape shape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape; | ||
699 | shape.RecalculateLocalAabb(); | ||
700 | } | ||
701 | |||
702 | //BulletSimAPI.GetCollisionFlags(PhysBody.ptr) | ||
703 | public override CollisionFlags GetCollisionFlags(BulletBody pBody) | ||
704 | { | ||
705 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
706 | uint flags = (uint)body.GetCollisionFlags(); | ||
707 | return (CollisionFlags) flags; | ||
708 | } | ||
709 | |||
710 | public override void SetDamping(BulletBody pBody, float pLinear, float pAngular) | ||
711 | { | ||
712 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
713 | body.SetDamping(pLinear, pAngular); | ||
714 | } | ||
715 | //PhysBody.ptr, PhysicsScene.Params.deactivationTime); | ||
716 | public override void SetDeactivationTime(BulletBody pBody, float pDeactivationTime) | ||
717 | { | ||
718 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
719 | body.SetDeactivationTime(pDeactivationTime); | ||
720 | } | ||
721 | //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); | ||
722 | public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold) | ||
723 | { | ||
724 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
725 | body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold); | ||
726 | } | ||
727 | |||
728 | public override CollisionObjectTypes GetBodyType(BulletBody pBody) | ||
729 | { | ||
730 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
731 | return (CollisionObjectTypes)(int) body.GetInternalType(); | ||
732 | } | ||
733 | |||
734 | public override void ApplyGravity(BulletBody obj) { /* TODO */ } | ||
735 | |||
736 | public override Vector3 GetGravity(BulletBody obj) { /* TODO */ return Vector3.Zero; } | ||
737 | |||
738 | public override void SetLinearDamping(BulletBody obj, float lin_damping) { /* TODO */ } | ||
739 | |||
740 | public override float GetLinearDamping(BulletBody obj) { /* TODO */ return 0f; } | ||
741 | |||
742 | public override float GetAngularDamping(BulletBody obj) { /* TODO */ return 0f; } | ||
743 | |||
744 | public override float GetLinearSleepingThreshold(BulletBody obj) { /* TODO */ return 0f; } | ||
745 | |||
746 | public override void ApplyDamping(BulletBody obj, float timeStep) { /* TODO */ } | ||
747 | |||
748 | public override Vector3 GetLinearFactor(BulletBody obj) { /* TODO */ return Vector3.Zero; } | ||
749 | |||
750 | public override void SetLinearFactor(BulletBody obj, Vector3 factor) { /* TODO */ } | ||
751 | |||
752 | public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) { /* TODO */ } | ||
753 | |||
754 | //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum); | ||
755 | public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum) | ||
756 | { | ||
757 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
758 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
759 | body.ApplyCentralForce(ref fSum); | ||
760 | } | ||
761 | public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum) | ||
762 | { | ||
763 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
764 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
765 | body.ApplyCentralImpulse(ref fSum); | ||
766 | } | ||
767 | public override void ApplyTorque(BulletBody pBody, Vector3 pfSum) | ||
768 | { | ||
769 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
770 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
771 | body.ApplyTorque(ref fSum); | ||
772 | } | ||
773 | public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum) | ||
774 | { | ||
775 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
776 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | ||
777 | body.ApplyTorqueImpulse(ref fSum); | ||
778 | } | ||
779 | |||
780 | public override void DestroyObject(BulletWorld p, BulletBody p_2) | ||
781 | { | ||
782 | //TODO: | ||
783 | } | ||
784 | |||
785 | public override void Shutdown(BulletWorld pWorld) | ||
786 | { | ||
787 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
788 | world.Cleanup(); | ||
789 | } | ||
790 | |||
791 | public override BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id) | ||
792 | { | ||
793 | return null; | ||
794 | } | ||
795 | |||
796 | public override bool DeleteCollisionShape(BulletWorld p, BulletShape p_2) | ||
797 | { | ||
798 | //TODO: | ||
799 | return false; | ||
800 | } | ||
801 | //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); | ||
802 | |||
803 | public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | ||
804 | { | ||
805 | CollisionWorld world = ((BulletWorldXNA)pWorld).world; | ||
806 | IndexedMatrix mat = | ||
807 | IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, | ||
808 | pRawOrientation.Z, pRawOrientation.W)); | ||
809 | mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | ||
810 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
811 | //UpdateSingleAabb(world, shape); | ||
812 | // TODO: Feed Update array into null | ||
813 | RigidBody body = new RigidBody(0,new SimMotionState(world,pLocalID,mat,null),shape,IndexedVector3.Zero); | ||
814 | |||
815 | body.SetUserPointer(pLocalID); | ||
816 | return new BulletBodyXNA(pLocalID, body); | ||
817 | } | ||
818 | |||
819 | |||
820 | public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | ||
821 | { | ||
822 | |||
823 | IndexedMatrix mat = | ||
824 | IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, | ||
825 | pRawOrientation.Z, pRawOrientation.W)); | ||
826 | mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | ||
827 | |||
828 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
829 | |||
830 | // TODO: Feed Update array into null | ||
831 | RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero); | ||
832 | body.SetWorldTransform(mat); | ||
833 | body.SetUserPointer(pLocalID); | ||
834 | return new BulletBodyXNA(pLocalID, body); | ||
835 | } | ||
836 | //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
837 | public override CollisionFlags SetCollisionFlags(BulletBody pBody, CollisionFlags collisionFlags) | ||
838 | { | ||
839 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
840 | body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags); | ||
841 | return (CollisionFlags)body.GetCollisionFlags(); | ||
842 | } | ||
843 | |||
844 | public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return Vector3.Zero; } | ||
845 | public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } | ||
846 | public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; } | ||
847 | public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; } | ||
848 | public override bool IsStaticObject(BulletBody pBody) { /* TODO */ return false; } | ||
849 | public override bool IsKinematicObject(BulletBody pBody) { /* TODO */ return false; } | ||
850 | public override bool IsStaticOrKinematicObject(BulletBody pBody) { /* TODO */ return false; } | ||
851 | public override bool HasContactResponse(BulletBody pBody) { /* TODO */ return false; } | ||
852 | public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; } | ||
853 | public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ } | ||
854 | public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; } | ||
855 | public override bool IsActive(BulletBody pBody) { /* TODO */ return false; } | ||
856 | public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; } | ||
857 | public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; } | ||
858 | public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ } | ||
859 | public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; } | ||
860 | |||
861 | //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); | ||
862 | public override void SetHitFraction(BulletBody pBody, float pHitFraction) | ||
863 | { | ||
864 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
865 | body.SetHitFraction(pHitFraction); | ||
866 | } | ||
867 | //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale); | ||
868 | public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale) | ||
869 | { | ||
870 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
871 | IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); | ||
872 | CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight); | ||
873 | capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
874 | capsuleShapeZ.SetLocalScaling(ref scale); | ||
875 | |||
876 | return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ; | ||
877 | } | ||
878 | |||
879 | public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, | ||
880 | int maxCollisions, ref CollisionDesc[] collisionArray, | ||
881 | int maxUpdates, ref EntityProperties[] updateArray | ||
882 | ) | ||
883 | { | ||
884 | /* TODO */ | ||
885 | return new BulletWorldXNA(1, null, null); | ||
886 | } | ||
887 | |||
888 | private static object Initialize2(Vector3 worldExtent, | ||
889 | ConfigurationParameters[] o, | ||
890 | int mMaxCollisionsPerFrame, ref List<BulletXNA.CollisionDesc> collisionArray, | ||
891 | int mMaxUpdatesPerFrame, ref List<BulletXNA.EntityProperties> updateArray, | ||
892 | object mDebugLogCallbackHandle) | ||
893 | { | ||
894 | CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); | ||
895 | |||
896 | p.angularDamping = o[0].XangularDamping; | ||
897 | p.defaultFriction = o[0].defaultFriction; | ||
898 | p.defaultFriction = o[0].defaultFriction; | ||
899 | p.defaultDensity = o[0].defaultDensity; | ||
900 | p.defaultRestitution = o[0].defaultRestitution; | ||
901 | p.collisionMargin = o[0].collisionMargin; | ||
902 | p.gravity = o[0].gravity; | ||
903 | |||
904 | p.linearDamping = o[0].XlinearDamping; | ||
905 | p.angularDamping = o[0].XangularDamping; | ||
906 | p.deactivationTime = o[0].XdeactivationTime; | ||
907 | p.linearSleepingThreshold = o[0].XlinearSleepingThreshold; | ||
908 | p.angularSleepingThreshold = o[0].XangularSleepingThreshold; | ||
909 | p.ccdMotionThreshold = o[0].XccdMotionThreshold; | ||
910 | p.ccdSweptSphereRadius = o[0].XccdSweptSphereRadius; | ||
911 | p.contactProcessingThreshold = o[0].XcontactProcessingThreshold; | ||
912 | |||
913 | p.terrainImplementation = o[0].XterrainImplementation; | ||
914 | p.terrainFriction = o[0].XterrainFriction; | ||
915 | |||
916 | p.terrainHitFraction = o[0].XterrainHitFraction; | ||
917 | p.terrainRestitution = o[0].XterrainRestitution; | ||
918 | p.terrainCollisionMargin = o[0].XterrainCollisionMargin; | ||
919 | |||
920 | p.avatarFriction = o[0].XavatarFriction; | ||
921 | p.avatarStandingFriction = o[0].XavatarStandingFriction; | ||
922 | p.avatarDensity = o[0].XavatarDensity; | ||
923 | p.avatarRestitution = o[0].XavatarRestitution; | ||
924 | p.avatarCapsuleWidth = o[0].XavatarCapsuleWidth; | ||
925 | p.avatarCapsuleDepth = o[0].XavatarCapsuleDepth; | ||
926 | p.avatarCapsuleHeight = o[0].XavatarCapsuleHeight; | ||
927 | p.avatarContactProcessingThreshold = o[0].XavatarContactProcessingThreshold; | ||
928 | |||
929 | p.vehicleAngularDamping = o[0].XvehicleAngularDamping; | ||
930 | |||
931 | p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; | ||
932 | p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; | ||
933 | p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; | ||
934 | p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs; | ||
935 | p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder; | ||
936 | p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands; | ||
937 | p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching; | ||
938 | p.numberOfSolverIterations = o[0].numberOfSolverIterations; | ||
939 | |||
940 | p.linksetImplementation = o[0].XlinksetImplementation; | ||
941 | p.linkConstraintUseFrameOffset = o[0].XlinkConstraintUseFrameOffset; | ||
942 | p.linkConstraintEnableTransMotor = o[0].XlinkConstraintEnableTransMotor; | ||
943 | p.linkConstraintTransMotorMaxVel = o[0].XlinkConstraintTransMotorMaxVel; | ||
944 | p.linkConstraintTransMotorMaxForce = o[0].XlinkConstraintTransMotorMaxForce; | ||
945 | p.linkConstraintERP = o[0].XlinkConstraintERP; | ||
946 | p.linkConstraintCFM = o[0].XlinkConstraintCFM; | ||
947 | p.linkConstraintSolverIterations = o[0].XlinkConstraintSolverIterations; | ||
948 | p.physicsLoggingFrames = o[0].XphysicsLoggingFrames; | ||
949 | DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); | ||
950 | |||
951 | DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); | ||
952 | CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); | ||
953 | |||
954 | |||
955 | if (p.maxPersistantManifoldPoolSize > 0) | ||
956 | cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize; | ||
957 | if (p.shouldDisableContactPoolDynamicAllocation !=0) | ||
958 | m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION); | ||
959 | //if (p.maxCollisionAlgorithmPoolSize >0 ) | ||
960 | |||
961 | DbvtBroadphase m_broadphase = new DbvtBroadphase(); | ||
962 | //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0); | ||
963 | //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256); | ||
964 | |||
965 | //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true); | ||
966 | m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback()); | ||
967 | |||
968 | SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver(); | ||
969 | |||
970 | DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci); | ||
971 | world.UpdatedObjects = updateArray; | ||
972 | world.UpdatedCollisions = collisionArray; | ||
973 | world.WorldSettings.Params = p; | ||
974 | world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0); | ||
975 | world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD; | ||
976 | if (p.shouldRandomizeSolverOrder != 0) | ||
977 | world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER; | ||
978 | |||
979 | world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0); | ||
980 | //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port | ||
981 | |||
982 | if (p.shouldEnableFrictionCaching != 0) | ||
983 | world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING; | ||
984 | |||
985 | if (p.numberOfSolverIterations > 0) | ||
986 | world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations; | ||
987 | |||
988 | |||
989 | world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping; | ||
990 | world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution; | ||
991 | world.GetSolverInfo().m_globalCfm = 0.0f; | ||
992 | world.GetSolverInfo().m_tau = 0.6f; | ||
993 | world.GetSolverInfo().m_friction = 0.3f; | ||
994 | world.GetSolverInfo().m_maxErrorReduction = 20f; | ||
995 | world.GetSolverInfo().m_numIterations = 10; | ||
996 | world.GetSolverInfo().m_erp = 0.2f; | ||
997 | world.GetSolverInfo().m_erp2 = 0.1f; | ||
998 | world.GetSolverInfo().m_sor = 1.0f; | ||
999 | world.GetSolverInfo().m_splitImpulse = false; | ||
1000 | world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f; | ||
1001 | world.GetSolverInfo().m_linearSlop = 0.0f; | ||
1002 | world.GetSolverInfo().m_warmstartingFactor = 0.85f; | ||
1003 | world.GetSolverInfo().m_restingContactRestitutionThreshold = 2; | ||
1004 | world.SetForceUpdateAllAabbs(true); | ||
1005 | |||
1006 | |||
1007 | world.SetGravity(new IndexedVector3(0,0,p.gravity)); | ||
1008 | |||
1009 | return world; | ||
1010 | } | ||
1011 | //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL | ||
1012 | public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis) | ||
1013 | { | ||
1014 | Generic6DofConstraint constrain = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | ||
1015 | if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) | ||
1016 | { | ||
1017 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0); | ||
1018 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1); | ||
1019 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2); | ||
1020 | } | ||
1021 | if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) | ||
1022 | { | ||
1023 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3); | ||
1024 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4); | ||
1025 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5); | ||
1026 | } | ||
1027 | if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL) | ||
1028 | { | ||
1029 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis); | ||
1030 | } | ||
1031 | return true; | ||
1032 | } | ||
1033 | |||
1034 | public override bool PushUpdate(BulletBody pCollisionObject) | ||
1035 | { | ||
1036 | bool ret = false; | ||
1037 | RigidBody rb = ((BulletBodyXNA)pCollisionObject).rigidBody; | ||
1038 | if (rb != null) | ||
1039 | { | ||
1040 | SimMotionState sms = rb.GetMotionState() as SimMotionState; | ||
1041 | if (sms != null) | ||
1042 | { | ||
1043 | IndexedMatrix wt = IndexedMatrix.Identity; | ||
1044 | sms.GetWorldTransform(out wt); | ||
1045 | sms.SetWorldTransform(ref wt, true); | ||
1046 | ret = true; | ||
1047 | } | ||
1048 | } | ||
1049 | return ret; | ||
1050 | |||
1051 | } | ||
1052 | |||
1053 | public override float GetAngularMotionDisc(BulletShape pShape) | ||
1054 | { | ||
1055 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
1056 | return shape.GetAngularMotionDisc(); | ||
1057 | } | ||
1058 | public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor) | ||
1059 | { | ||
1060 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
1061 | return shape.GetContactBreakingThreshold(defaultFactor); | ||
1062 | } | ||
1063 | public override bool IsCompound(BulletShape pShape) | ||
1064 | { | ||
1065 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
1066 | return shape.IsCompound(); | ||
1067 | } | ||
1068 | public override bool IsSoftBody(BulletShape pShape) | ||
1069 | { | ||
1070 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
1071 | return shape.IsSoftBody(); | ||
1072 | } | ||
1073 | public override bool IsPolyhedral(BulletShape pShape) | ||
1074 | { | ||
1075 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
1076 | return shape.IsPolyhedral(); | ||
1077 | } | ||
1078 | public override bool IsConvex2d(BulletShape pShape) | ||
1079 | { | ||
1080 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
1081 | return shape.IsConvex2d(); | ||
1082 | } | ||
1083 | public override bool IsConvex(BulletShape pShape) | ||
1084 | { | ||
1085 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
1086 | return shape.IsConvex(); | ||
1087 | } | ||
1088 | public override bool IsNonMoving(BulletShape pShape) | ||
1089 | { | ||
1090 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
1091 | return shape.IsNonMoving(); | ||
1092 | } | ||
1093 | public override bool IsConcave(BulletShape pShape) | ||
1094 | { | ||
1095 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
1096 | return shape.IsConcave(); | ||
1097 | } | ||
1098 | public override bool IsInfinite(BulletShape pShape) | ||
1099 | { | ||
1100 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
1101 | return shape.IsInfinite(); | ||
1102 | } | ||
1103 | public override bool IsNativeShape(BulletShape pShape) | ||
1104 | { | ||
1105 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
1106 | bool ret; | ||
1107 | switch (shape.GetShapeType()) | ||
1108 | { | ||
1109 | case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: | ||
1110 | case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: | ||
1111 | case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: | ||
1112 | case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: | ||
1113 | ret = true; | ||
1114 | break; | ||
1115 | default: | ||
1116 | ret = false; | ||
1117 | break; | ||
1118 | } | ||
1119 | return ret; | ||
1120 | } | ||
1121 | |||
1122 | public override void SetShapeCollisionMargin(BulletShape shape, float margin) { /* TODO */ } | ||
1123 | |||
1124 | //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation | ||
1125 | public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | ||
1126 | { | ||
1127 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
1128 | IndexedMatrix bodyTransform = new IndexedMatrix(); | ||
1129 | bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | ||
1130 | bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W)); | ||
1131 | GhostObject gObj = new PairCachingGhostObject(); | ||
1132 | gObj.SetWorldTransform(bodyTransform); | ||
1133 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
1134 | gObj.SetCollisionShape(shape); | ||
1135 | gObj.SetUserPointer(pLocalID); | ||
1136 | // TODO: Add to Special CollisionObjects! | ||
1137 | return new BulletBodyXNA(pLocalID, gObj); | ||
1138 | } | ||
1139 | |||
1140 | public override void SetCollisionShape(BulletWorld pWorld, BulletBody pObj, BulletShape pShape) | ||
1141 | { | ||
1142 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
1143 | CollisionObject obj = ((BulletBodyXNA)pObj).body; | ||
1144 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
1145 | obj.SetCollisionShape(shape); | ||
1146 | |||
1147 | } | ||
1148 | public override BulletShape GetCollisionShape(BulletBody obj) { /* TODO */ return null; } | ||
1149 | |||
1150 | //(PhysicsScene.World.ptr, nativeShapeData) | ||
1151 | public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData) | ||
1152 | { | ||
1153 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
1154 | CollisionShape shape = null; | ||
1155 | switch (pShapeData.Type) | ||
1156 | { | ||
1157 | case BSPhysicsShapeType.SHAPE_BOX: | ||
1158 | shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f)); | ||
1159 | break; | ||
1160 | case BSPhysicsShapeType.SHAPE_CONE: | ||
1161 | shape = new ConeShapeZ(0.5f, 1.0f); | ||
1162 | break; | ||
1163 | case BSPhysicsShapeType.SHAPE_CYLINDER: | ||
1164 | shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f)); | ||
1165 | break; | ||
1166 | case BSPhysicsShapeType.SHAPE_SPHERE: | ||
1167 | shape = new SphereShape(0.5f); | ||
1168 | break; | ||
1169 | |||
1170 | } | ||
1171 | if (shape != null) | ||
1172 | { | ||
1173 | IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z); | ||
1174 | shape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1175 | shape.SetLocalScaling(ref scaling); | ||
1176 | |||
1177 | } | ||
1178 | return new BulletShapeXNA(shape, pShapeData.Type); | ||
1179 | } | ||
1180 | //PhysicsScene.World.ptr, false | ||
1181 | public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree) | ||
1182 | { | ||
1183 | return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND); | ||
1184 | } | ||
1185 | |||
1186 | public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape) | ||
1187 | { | ||
1188 | CompoundShape compoundshape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape; | ||
1189 | return compoundshape.GetNumChildShapes(); | ||
1190 | } | ||
1191 | //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot | ||
1192 | public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot) | ||
1193 | { | ||
1194 | IndexedMatrix relativeTransform = new IndexedMatrix(); | ||
1195 | CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape; | ||
1196 | CollisionShape addshape = ((BulletShapeXNA)paddShape).shape; | ||
1197 | |||
1198 | relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z); | ||
1199 | relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W)); | ||
1200 | compoundshape.AddChildShape(ref relativeTransform, addshape); | ||
1201 | |||
1202 | } | ||
1203 | |||
1204 | public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii) | ||
1205 | { | ||
1206 | CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape; | ||
1207 | CollisionShape ret = null; | ||
1208 | ret = compoundshape.GetChildShape(pii); | ||
1209 | compoundshape.RemoveChildShapeByIndex(pii); | ||
1210 | return new BulletShapeXNA(ret, BSPhysicsShapeType.SHAPE_UNKNOWN); | ||
1211 | } | ||
1212 | |||
1213 | public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { /* TODO */ return null; } | ||
1214 | public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ } | ||
1215 | |||
1216 | public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin) | ||
1217 | { | ||
1218 | StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight ); | ||
1219 | m_planeshape.SetMargin(pcollisionMargin); | ||
1220 | m_planeshape.SetUserPointer(pLocalId); | ||
1221 | return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); | ||
1222 | } | ||
1223 | |||
1224 | public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody ppBody2, Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
1225 | { | ||
1226 | HingeConstraint constrain = null; | ||
1227 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
1228 | RigidBody rb1 = ((BulletBodyXNA)pBody1).rigidBody; | ||
1229 | RigidBody rb2 = ((BulletBodyXNA)ppBody2).rigidBody; | ||
1230 | if (rb1 != null && rb2 != null) | ||
1231 | { | ||
1232 | IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); | ||
1233 | IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); | ||
1234 | IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); | ||
1235 | IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); | ||
1236 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1237 | } | ||
1238 | return new BulletConstraintXNA(constrain); | ||
1239 | } | ||
1240 | |||
1241 | public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls) | ||
1242 | { | ||
1243 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
1244 | CompoundShape compoundshape = new CompoundShape(false); | ||
1245 | |||
1246 | compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1247 | int ii = 1; | ||
1248 | |||
1249 | for (int i = 0; i < pHullCount; i++) | ||
1250 | { | ||
1251 | int vertexCount = (int) pConvHulls[ii]; | ||
1252 | |||
1253 | IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]); | ||
1254 | IndexedMatrix childTrans = IndexedMatrix.Identity; | ||
1255 | childTrans._origin = centroid; | ||
1256 | |||
1257 | List<IndexedVector3> virts = new List<IndexedVector3>(); | ||
1258 | int ender = ((ii + 4) + (vertexCount*3)); | ||
1259 | for (int iii = ii + 4; iii < ender; iii+=3) | ||
1260 | { | ||
1261 | |||
1262 | virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); | ||
1263 | } | ||
1264 | ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); | ||
1265 | convexShape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1266 | compoundshape.AddChildShape(ref childTrans, convexShape); | ||
1267 | ii += (vertexCount*3 + 4); | ||
1268 | } | ||
1269 | |||
1270 | return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); | ||
1271 | } | ||
1272 | |||
1273 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) { /* TODO */ return null; } | ||
1274 | |||
1275 | public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | ||
1276 | { | ||
1277 | //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); | ||
1278 | |||
1279 | for (int iter = 0; iter < pVerticesCount; iter++) | ||
1280 | { | ||
1281 | if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; | ||
1282 | if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; | ||
1283 | } | ||
1284 | |||
1285 | ObjectArray<int> indicesarr = new ObjectArray<int>(indices); | ||
1286 | ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); | ||
1287 | DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); | ||
1288 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
1289 | IndexedMesh mesh = new IndexedMesh(); | ||
1290 | mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; | ||
1291 | mesh.m_numTriangles = pIndicesCount/3; | ||
1292 | mesh.m_numVertices = pVerticesCount; | ||
1293 | mesh.m_triangleIndexBase = indicesarr; | ||
1294 | mesh.m_vertexBase = vertices; | ||
1295 | mesh.m_vertexStride = 3; | ||
1296 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | ||
1297 | mesh.m_triangleIndexStride = 3; | ||
1298 | |||
1299 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | ||
1300 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | ||
1301 | BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); | ||
1302 | meshShape.SetMargin(world.WorldSettings.Params.collisionMargin); | ||
1303 | // world.UpdateSingleAabb(meshShape); | ||
1304 | return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); | ||
1305 | |||
1306 | } | ||
1307 | public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) | ||
1308 | { | ||
1309 | |||
1310 | String fileName = "objTest3.raw"; | ||
1311 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); | ||
1312 | StreamWriter sw = new StreamWriter(completePath); | ||
1313 | IndexedMesh mesh = new IndexedMesh(); | ||
1314 | |||
1315 | mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; | ||
1316 | mesh.m_numTriangles = pIndicesCount / 3; | ||
1317 | mesh.m_numVertices = pVerticesCount; | ||
1318 | mesh.m_triangleIndexBase = indices; | ||
1319 | mesh.m_vertexBase = vertices; | ||
1320 | mesh.m_vertexStride = 3; | ||
1321 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | ||
1322 | mesh.m_triangleIndexStride = 3; | ||
1323 | |||
1324 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | ||
1325 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | ||
1326 | |||
1327 | |||
1328 | |||
1329 | for (int i = 0; i < pVerticesCount; i++) | ||
1330 | { | ||
1331 | |||
1332 | string s = vertices[indices[i * 3]].ToString("0.0000"); | ||
1333 | s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); | ||
1334 | s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); | ||
1335 | |||
1336 | sw.Write(s + "\n"); | ||
1337 | } | ||
1338 | |||
1339 | sw.Close(); | ||
1340 | } | ||
1341 | public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount) | ||
1342 | { | ||
1343 | |||
1344 | String fileName = "objTest6.raw"; | ||
1345 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); | ||
1346 | StreamWriter sw = new StreamWriter(completePath); | ||
1347 | IndexedMesh mesh = new IndexedMesh(); | ||
1348 | |||
1349 | mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; | ||
1350 | mesh.m_numTriangles = pIndicesCount / 3; | ||
1351 | mesh.m_numVertices = pVerticesCount; | ||
1352 | mesh.m_triangleIndexBase = indices; | ||
1353 | mesh.m_vertexBase = vertices; | ||
1354 | mesh.m_vertexStride = 3; | ||
1355 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | ||
1356 | mesh.m_triangleIndexStride = 3; | ||
1357 | |||
1358 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | ||
1359 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | ||
1360 | |||
1361 | |||
1362 | sw.WriteLine("Indices"); | ||
1363 | sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount)); | ||
1364 | for (int iter = 0; iter < indices.Length; iter++) | ||
1365 | { | ||
1366 | sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter])); | ||
1367 | } | ||
1368 | sw.WriteLine("VerticesFloats"); | ||
1369 | sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount)); | ||
1370 | for (int iter = 0; iter < vertices.Length; iter++) | ||
1371 | { | ||
1372 | sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000"))); | ||
1373 | } | ||
1374 | |||
1375 | // for (int i = 0; i < pVerticesCount; i++) | ||
1376 | // { | ||
1377 | // | ||
1378 | // string s = vertices[indices[i * 3]].ToString("0.0000"); | ||
1379 | // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); | ||
1380 | // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); | ||
1381 | // | ||
1382 | // sw.Write(s + "\n"); | ||
1383 | //} | ||
1384 | |||
1385 | sw.Close(); | ||
1386 | } | ||
1387 | |||
1388 | public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | ||
1389 | float scaleFactor, float collisionMargin) | ||
1390 | { | ||
1391 | const int upAxis = 2; | ||
1392 | HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y, | ||
1393 | heightMap, scaleFactor, | ||
1394 | minHeight, maxHeight, upAxis, | ||
1395 | false); | ||
1396 | terrainShape.SetMargin(collisionMargin + 0.5f); | ||
1397 | terrainShape.SetUseDiamondSubdivision(true); | ||
1398 | terrainShape.SetUserPointer(id); | ||
1399 | return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN); | ||
1400 | } | ||
1401 | |||
1402 | public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce) | ||
1403 | { | ||
1404 | TypedConstraint tconstrain = ((BulletConstraintXNA)pConstraint).constrain; | ||
1405 | bool onOff = ponOff != 0; | ||
1406 | bool ret = false; | ||
1407 | |||
1408 | switch (tconstrain.GetConstraintType()) | ||
1409 | { | ||
1410 | case TypedConstraintType.D6_CONSTRAINT_TYPE: | ||
1411 | Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint; | ||
1412 | constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff; | ||
1413 | constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity; | ||
1414 | constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce; | ||
1415 | ret = true; | ||
1416 | break; | ||
1417 | } | ||
1418 | |||
1419 | |||
1420 | return ret; | ||
1421 | |||
1422 | } | ||
1423 | |||
1424 | public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, | ||
1425 | out int updatedEntityCount, out int collidersCount) | ||
1426 | { | ||
1427 | /* TODO */ | ||
1428 | updatedEntityCount = 0; | ||
1429 | collidersCount = 0; | ||
1430 | return 1; | ||
1431 | } | ||
1432 | |||
1433 | private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, | ||
1434 | out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, | ||
1435 | out int collidersCount, out List<BulletXNA.CollisionDesc>colliders) | ||
1436 | { | ||
1437 | int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities, | ||
1438 | out collidersCount, out colliders); | ||
1439 | return epic; | ||
1440 | } | ||
1441 | |||
1442 | private static int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, out int collidersCount, out List<BulletXNA.CollisionDesc> colliders) | ||
1443 | { | ||
1444 | int numSimSteps = 0; | ||
1445 | |||
1446 | |||
1447 | //if (updatedEntities is null) | ||
1448 | // updatedEntities = new List<BulletXNA.EntityProperties>(); | ||
1449 | |||
1450 | //if (colliders is null) | ||
1451 | // colliders = new List<BulletXNA.CollisionDesc>(); | ||
1452 | |||
1453 | |||
1454 | if (pWorld is BulletWorldXNA) | ||
1455 | { | ||
1456 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
1457 | |||
1458 | numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep); | ||
1459 | int updates = 0; | ||
1460 | |||
1461 | updatedEntityCount = world.UpdatedObjects.Count; | ||
1462 | updatedEntities = new List<BulletXNA.EntityProperties>(world.UpdatedObjects); | ||
1463 | updatedEntityCount = updatedEntities.Count; | ||
1464 | world.UpdatedObjects.Clear(); | ||
1465 | |||
1466 | |||
1467 | collidersCount = world.UpdatedCollisions.Count; | ||
1468 | colliders = new List<BulletXNA.CollisionDesc>(world.UpdatedCollisions); | ||
1469 | |||
1470 | world.UpdatedCollisions.Clear(); | ||
1471 | m_collisionsThisFrame = 0; | ||
1472 | int numManifolds = world.GetDispatcher().GetNumManifolds(); | ||
1473 | for (int j = 0; j < numManifolds; j++) | ||
1474 | { | ||
1475 | PersistentManifold contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j); | ||
1476 | int numContacts = contactManifold.GetNumContacts(); | ||
1477 | if (numContacts == 0) | ||
1478 | continue; | ||
1479 | |||
1480 | CollisionObject objA = contactManifold.GetBody0() as CollisionObject; | ||
1481 | CollisionObject objB = contactManifold.GetBody1() as CollisionObject; | ||
1482 | |||
1483 | ManifoldPoint manifoldPoint = contactManifold.GetContactPoint(0); | ||
1484 | IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB(); | ||
1485 | IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A | ||
1486 | |||
1487 | RecordCollision(world, objA, objB, contactPoint, contactNormal); | ||
1488 | m_collisionsThisFrame ++; | ||
1489 | if (m_collisionsThisFrame >= 9999999) | ||
1490 | break; | ||
1491 | |||
1492 | |||
1493 | } | ||
1494 | |||
1495 | |||
1496 | } | ||
1497 | else | ||
1498 | { | ||
1499 | //if (updatedEntities is null) | ||
1500 | updatedEntities = new List<BulletXNA.EntityProperties>(); | ||
1501 | updatedEntityCount = 0; | ||
1502 | //if (colliders is null) | ||
1503 | colliders = new List<BulletXNA.CollisionDesc>(); | ||
1504 | collidersCount = 0; | ||
1505 | } | ||
1506 | return numSimSteps; | ||
1507 | } | ||
1508 | |||
1509 | private static void RecordCollision(CollisionWorld world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm) | ||
1510 | { | ||
1511 | |||
1512 | IndexedVector3 contactNormal = norm; | ||
1513 | if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && | ||
1514 | (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) | ||
1515 | { | ||
1516 | return; | ||
1517 | } | ||
1518 | uint idA = (uint)objA.GetUserPointer(); | ||
1519 | uint idB = (uint)objB.GetUserPointer(); | ||
1520 | if (idA > idB) | ||
1521 | { | ||
1522 | uint temp = idA; | ||
1523 | idA = idB; | ||
1524 | idB = temp; | ||
1525 | contactNormal = -contactNormal; | ||
1526 | } | ||
1527 | |||
1528 | ulong collisionID = ((ulong) idA << 32) | idB; | ||
1529 | |||
1530 | BulletXNA.CollisionDesc cDesc = new BulletXNA.CollisionDesc() | ||
1531 | { | ||
1532 | aID = idA, | ||
1533 | bID = idB, | ||
1534 | point = contact, | ||
1535 | normal = contactNormal | ||
1536 | }; | ||
1537 | world.UpdatedCollisions.Add(cDesc); | ||
1538 | m_collisionsThisFrame++; | ||
1539 | |||
1540 | |||
1541 | } | ||
1542 | private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pBody) | ||
1543 | { | ||
1544 | EntityProperties ent = new EntityProperties(); | ||
1545 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
1546 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | ||
1547 | IndexedMatrix transform = body.GetWorldTransform(); | ||
1548 | IndexedVector3 LinearVelocity = body.GetInterpolationLinearVelocity(); | ||
1549 | IndexedVector3 AngularVelocity = body.GetInterpolationAngularVelocity(); | ||
1550 | IndexedQuaternion rotation = transform.GetRotation(); | ||
1551 | ent.Acceleration = Vector3.Zero; | ||
1552 | ent.ID = (uint)body.GetUserPointer(); | ||
1553 | ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z); | ||
1554 | ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W); | ||
1555 | ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z); | ||
1556 | ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z); | ||
1557 | return ent; | ||
1558 | } | ||
1559 | |||
1560 | public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */ return false; } | ||
1561 | |||
1562 | public override Vector3 GetLocalScaling(BulletShape pShape) | ||
1563 | { | ||
1564 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | ||
1565 | IndexedVector3 scale = shape.GetLocalScaling(); | ||
1566 | return new Vector3(scale.X,scale.Y,scale.Z); | ||
1567 | } | ||
1568 | |||
1569 | public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe) | ||
1570 | { | ||
1571 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | ||
1572 | if (world != null) | ||
1573 | { | ||
1574 | if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) | ||
1575 | { | ||
1576 | CollisionObject AvoidBody = ((BulletBodyXNA)NotMe).body; | ||
1577 | |||
1578 | IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); | ||
1579 | IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); | ||
1580 | using ( | ||
1581 | ClosestNotMeRayResultCallback rayCallback = | ||
1582 | new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) | ||
1583 | ) | ||
1584 | { | ||
1585 | world.RayTest(ref rOrigin, ref rEnd, rayCallback); | ||
1586 | if (rayCallback.HasHit()) | ||
1587 | { | ||
1588 | IndexedVector3 hitLocation = rayCallback.m_hitPointWorld; | ||
1589 | } | ||
1590 | return rayCallback.HasHit(); | ||
1591 | } | ||
1592 | } | ||
1593 | } | ||
1594 | return false; | ||
1595 | } | ||
1596 | } | ||
1597 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs new file mode 100644 index 0000000..befb076 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs | |||
@@ -0,0 +1,666 @@ | |||
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.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 | MAX_CONSTRAINT_TYPE | ||
47 | } | ||
48 | |||
49 | // =============================================================================== | ||
50 | [StructLayout(LayoutKind.Sequential)] | ||
51 | public struct ConvexHull | ||
52 | { | ||
53 | Vector3 Offset; | ||
54 | int VertexCount; | ||
55 | Vector3[] Vertices; | ||
56 | } | ||
57 | public enum BSPhysicsShapeType | ||
58 | { | ||
59 | SHAPE_UNKNOWN = 0, | ||
60 | SHAPE_CAPSULE = 1, | ||
61 | SHAPE_BOX = 2, | ||
62 | SHAPE_CONE = 3, | ||
63 | SHAPE_CYLINDER = 4, | ||
64 | SHAPE_SPHERE = 5, | ||
65 | SHAPE_MESH = 6, | ||
66 | SHAPE_HULL = 7, | ||
67 | // following defined by BulletSim | ||
68 | SHAPE_GROUNDPLANE = 20, | ||
69 | SHAPE_TERRAIN = 21, | ||
70 | SHAPE_COMPOUND = 22, | ||
71 | SHAPE_HEIGHTMAP = 23, | ||
72 | SHAPE_AVATAR = 24, | ||
73 | }; | ||
74 | |||
75 | // The native shapes have predefined shape hash keys | ||
76 | public enum FixedShapeKey : ulong | ||
77 | { | ||
78 | KEY_NONE = 0, | ||
79 | KEY_BOX = 1, | ||
80 | KEY_SPHERE = 2, | ||
81 | KEY_CONE = 3, | ||
82 | KEY_CYLINDER = 4, | ||
83 | KEY_CAPSULE = 5, | ||
84 | KEY_AVATAR = 6, | ||
85 | } | ||
86 | |||
87 | [StructLayout(LayoutKind.Sequential)] | ||
88 | public struct ShapeData | ||
89 | { | ||
90 | public uint ID; | ||
91 | public BSPhysicsShapeType Type; | ||
92 | public Vector3 Position; | ||
93 | public Quaternion Rotation; | ||
94 | public Vector3 Velocity; | ||
95 | public Vector3 Scale; | ||
96 | public float Mass; | ||
97 | public float Buoyancy; | ||
98 | public System.UInt64 HullKey; | ||
99 | public System.UInt64 MeshKey; | ||
100 | public float Friction; | ||
101 | public float Restitution; | ||
102 | public float Collidable; // true of things bump into this | ||
103 | public float Static; // true if a static object. Otherwise gravity, etc. | ||
104 | public float Solid; // true if object cannot be passed through | ||
105 | public Vector3 Size; | ||
106 | |||
107 | // note that bools are passed as floats since bool size changes by language and architecture | ||
108 | public const float numericTrue = 1f; | ||
109 | public const float numericFalse = 0f; | ||
110 | } | ||
111 | [StructLayout(LayoutKind.Sequential)] | ||
112 | public struct SweepHit | ||
113 | { | ||
114 | public uint ID; | ||
115 | public float Fraction; | ||
116 | public Vector3 Normal; | ||
117 | public Vector3 Point; | ||
118 | } | ||
119 | [StructLayout(LayoutKind.Sequential)] | ||
120 | public struct RaycastHit | ||
121 | { | ||
122 | public uint ID; | ||
123 | public float Fraction; | ||
124 | public Vector3 Normal; | ||
125 | } | ||
126 | [StructLayout(LayoutKind.Sequential)] | ||
127 | public struct CollisionDesc | ||
128 | { | ||
129 | public uint aID; | ||
130 | public uint bID; | ||
131 | public Vector3 point; | ||
132 | public Vector3 normal; | ||
133 | } | ||
134 | [StructLayout(LayoutKind.Sequential)] | ||
135 | public struct EntityProperties | ||
136 | { | ||
137 | public uint ID; | ||
138 | public Vector3 Position; | ||
139 | public Quaternion Rotation; | ||
140 | public Vector3 Velocity; | ||
141 | public Vector3 Acceleration; | ||
142 | public Vector3 RotationalVelocity; | ||
143 | } | ||
144 | |||
145 | // Format of this structure must match the definition in the C++ code | ||
146 | // NOTE: adding the X causes compile breaks if used. These are unused symbols | ||
147 | // that can be removed from both here and the unmanaged definition of this structure. | ||
148 | [StructLayout(LayoutKind.Sequential)] | ||
149 | public struct ConfigurationParameters | ||
150 | { | ||
151 | public float defaultFriction; | ||
152 | public float defaultDensity; | ||
153 | public float defaultRestitution; | ||
154 | public float collisionMargin; | ||
155 | public float gravity; | ||
156 | |||
157 | public float XlinearDamping; | ||
158 | public float XangularDamping; | ||
159 | public float XdeactivationTime; | ||
160 | public float XlinearSleepingThreshold; | ||
161 | public float XangularSleepingThreshold; | ||
162 | public float XccdMotionThreshold; | ||
163 | public float XccdSweptSphereRadius; | ||
164 | public float XcontactProcessingThreshold; | ||
165 | |||
166 | public float XterrainImplementation; | ||
167 | public float XterrainFriction; | ||
168 | public float XterrainHitFraction; | ||
169 | public float XterrainRestitution; | ||
170 | public float XterrainCollisionMargin; | ||
171 | |||
172 | public float XavatarFriction; | ||
173 | public float XavatarStandingFriction; | ||
174 | public float XavatarDensity; | ||
175 | public float XavatarRestitution; | ||
176 | public float XavatarCapsuleWidth; | ||
177 | public float XavatarCapsuleDepth; | ||
178 | public float XavatarCapsuleHeight; | ||
179 | public float XavatarContactProcessingThreshold; | ||
180 | |||
181 | public float XvehicleAngularDamping; | ||
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 | |||
192 | public float XlinksetImplementation; | ||
193 | public float XlinkConstraintUseFrameOffset; | ||
194 | public float XlinkConstraintEnableTransMotor; | ||
195 | public float XlinkConstraintTransMotorMaxVel; | ||
196 | public float XlinkConstraintTransMotorMaxForce; | ||
197 | public float XlinkConstraintERP; | ||
198 | public float XlinkConstraintCFM; | ||
199 | public float XlinkConstraintSolverIterations; | ||
200 | |||
201 | public float XphysicsLoggingFrames; | ||
202 | |||
203 | public const float numericTrue = 1f; | ||
204 | public const float numericFalse = 0f; | ||
205 | } | ||
206 | |||
207 | |||
208 | // The states a bullet collision object can have | ||
209 | public enum ActivationState : uint | ||
210 | { | ||
211 | ACTIVE_TAG = 1, | ||
212 | ISLAND_SLEEPING, | ||
213 | WANTS_DEACTIVATION, | ||
214 | DISABLE_DEACTIVATION, | ||
215 | DISABLE_SIMULATION, | ||
216 | } | ||
217 | |||
218 | public enum CollisionObjectTypes : int | ||
219 | { | ||
220 | CO_COLLISION_OBJECT = 1 << 0, | ||
221 | CO_RIGID_BODY = 1 << 1, | ||
222 | CO_GHOST_OBJECT = 1 << 2, | ||
223 | CO_SOFT_BODY = 1 << 3, | ||
224 | CO_HF_FLUID = 1 << 4, | ||
225 | CO_USER_TYPE = 1 << 5, | ||
226 | } | ||
227 | |||
228 | // Values used by Bullet and BulletSim to control object properties. | ||
229 | // Bullet's "CollisionFlags" has more to do with operations on the | ||
230 | // object (if collisions happen, if gravity effects it, ...). | ||
231 | public enum CollisionFlags : uint | ||
232 | { | ||
233 | CF_STATIC_OBJECT = 1 << 0, | ||
234 | CF_KINEMATIC_OBJECT = 1 << 1, | ||
235 | CF_NO_CONTACT_RESPONSE = 1 << 2, | ||
236 | CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3, | ||
237 | CF_CHARACTER_OBJECT = 1 << 4, | ||
238 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, | ||
239 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, | ||
240 | // Following used by BulletSim to control collisions and updates | ||
241 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, | ||
242 | BS_FLOATS_ON_WATER = 1 << 11, | ||
243 | BS_VEHICLE_COLLISIONS = 1 << 12, | ||
244 | BS_NONE = 0, | ||
245 | BS_ALL = 0xFFFFFFFF | ||
246 | }; | ||
247 | |||
248 | // Values f collisions groups and masks | ||
249 | public enum CollisionFilterGroups : uint | ||
250 | { | ||
251 | // Don't use the bit definitions!! Define the use in a | ||
252 | // filter/mask definition below. This way collision interactions | ||
253 | // are more easily found and debugged. | ||
254 | BNoneGroup = 0, | ||
255 | BDefaultGroup = 1 << 0, // 0001 | ||
256 | BStaticGroup = 1 << 1, // 0002 | ||
257 | BKinematicGroup = 1 << 2, // 0004 | ||
258 | BDebrisGroup = 1 << 3, // 0008 | ||
259 | BSensorTrigger = 1 << 4, // 0010 | ||
260 | BCharacterGroup = 1 << 5, // 0020 | ||
261 | BAllGroup = 0x000FFFFF, | ||
262 | // Filter groups defined by BulletSim | ||
263 | BGroundPlaneGroup = 1 << 10, // 0400 | ||
264 | BTerrainGroup = 1 << 11, // 0800 | ||
265 | BRaycastGroup = 1 << 12, // 1000 | ||
266 | BSolidGroup = 1 << 13, // 2000 | ||
267 | // BLinksetGroup = xx // a linkset proper is either static or dynamic | ||
268 | BLinksetChildGroup = 1 << 14, // 4000 | ||
269 | }; | ||
270 | |||
271 | // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 | ||
272 | // ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. | ||
273 | public enum ConstraintParams : int | ||
274 | { | ||
275 | BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730 | ||
276 | BT_CONSTRAINT_STOP_ERP, | ||
277 | BT_CONSTRAINT_CFM, | ||
278 | BT_CONSTRAINT_STOP_CFM, | ||
279 | }; | ||
280 | public enum ConstraintParamAxis : int | ||
281 | { | ||
282 | AXIS_LINEAR_X = 0, | ||
283 | AXIS_LINEAR_Y, | ||
284 | AXIS_LINEAR_Z, | ||
285 | AXIS_ANGULAR_X, | ||
286 | AXIS_ANGULAR_Y, | ||
287 | AXIS_ANGULAR_Z, | ||
288 | AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls | ||
289 | AXIS_ANGULAR_ALL, | ||
290 | AXIS_ALL | ||
291 | }; | ||
292 | |||
293 | public abstract class BSAPITemplate | ||
294 | { | ||
295 | // Returns the name of the underlying Bullet engine | ||
296 | public abstract string BulletEngineName { get; } | ||
297 | public abstract string BulletEngineVersion { get; protected set;} | ||
298 | |||
299 | // Initialization and simulation | ||
300 | public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, | ||
301 | int maxCollisions, ref CollisionDesc[] collisionArray, | ||
302 | int maxUpdates, ref EntityProperties[] updateArray | ||
303 | ); | ||
304 | |||
305 | public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, | ||
306 | out int updatedEntityCount, out int collidersCount); | ||
307 | |||
308 | public abstract bool UpdateParameter(BulletWorld world, uint localID, String parm, float value); | ||
309 | |||
310 | public abstract void Shutdown(BulletWorld sim); | ||
311 | |||
312 | public abstract bool PushUpdate(BulletBody obj); | ||
313 | |||
314 | // ===================================================================================== | ||
315 | // Mesh, hull, shape and body creation helper routines | ||
316 | public abstract BulletShape CreateMeshShape(BulletWorld world, | ||
317 | int indicesCount, int[] indices, | ||
318 | int verticesCount, float[] vertices ); | ||
319 | |||
320 | public abstract BulletShape CreateHullShape(BulletWorld world, | ||
321 | int hullCount, float[] hulls); | ||
322 | |||
323 | public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape); | ||
324 | |||
325 | public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); | ||
326 | |||
327 | public abstract bool IsNativeShape(BulletShape shape); | ||
328 | |||
329 | public abstract void SetShapeCollisionMargin(BulletShape shape, float margin); | ||
330 | |||
331 | public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale); | ||
332 | |||
333 | public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree); | ||
334 | |||
335 | public abstract int GetNumberOfCompoundChildren(BulletShape cShape); | ||
336 | |||
337 | public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot); | ||
338 | |||
339 | public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx); | ||
340 | |||
341 | public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx); | ||
342 | |||
343 | public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape); | ||
344 | |||
345 | public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape); | ||
346 | |||
347 | public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id); | ||
348 | |||
349 | public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape); | ||
350 | |||
351 | public abstract CollisionObjectTypes GetBodyType(BulletBody obj); | ||
352 | |||
353 | public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot); | ||
354 | |||
355 | public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot); | ||
356 | |||
357 | public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot); | ||
358 | |||
359 | public abstract void DestroyObject(BulletWorld sim, BulletBody obj); | ||
360 | |||
361 | // ===================================================================================== | ||
362 | public abstract BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin); | ||
363 | |||
364 | public abstract BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | ||
365 | float scaleFactor, float collisionMargin); | ||
366 | |||
367 | // ===================================================================================== | ||
368 | // Constraint creation and helper routines | ||
369 | public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
370 | Vector3 frame1loc, Quaternion frame1rot, | ||
371 | Vector3 frame2loc, Quaternion frame2rot, | ||
372 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
373 | |||
374 | public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
375 | Vector3 joinPoint, | ||
376 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
377 | |||
378 | public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
379 | Vector3 pivotinA, Vector3 pivotinB, | ||
380 | Vector3 axisInA, Vector3 axisInB, | ||
381 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
382 | |||
383 | public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse); | ||
384 | |||
385 | public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations); | ||
386 | |||
387 | public abstract bool SetFrames(BulletConstraint constrain, | ||
388 | Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); | ||
389 | |||
390 | public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi); | ||
391 | |||
392 | public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi); | ||
393 | |||
394 | public abstract bool UseFrameOffset(BulletConstraint constrain, float enable); | ||
395 | |||
396 | public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce); | ||
397 | |||
398 | public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold); | ||
399 | |||
400 | public abstract bool CalculateTransforms(BulletConstraint constrain); | ||
401 | |||
402 | public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); | ||
403 | |||
404 | public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain); | ||
405 | |||
406 | // ===================================================================================== | ||
407 | // btCollisionWorld entries | ||
408 | public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj); | ||
409 | |||
410 | public abstract void UpdateAabbs(BulletWorld world); | ||
411 | |||
412 | public abstract bool GetForceUpdateAllAabbs(BulletWorld world); | ||
413 | |||
414 | public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force); | ||
415 | |||
416 | // ===================================================================================== | ||
417 | // btDynamicsWorld entries | ||
418 | // public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot); | ||
419 | public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj); | ||
420 | |||
421 | public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj); | ||
422 | |||
423 | public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects); | ||
424 | |||
425 | public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain); | ||
426 | // ===================================================================================== | ||
427 | // btCollisionObject entries | ||
428 | public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain); | ||
429 | |||
430 | public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict); | ||
431 | |||
432 | public abstract bool HasAnisotripicFriction(BulletConstraint constrain); | ||
433 | |||
434 | public abstract void SetContactProcessingThreshold(BulletBody obj, float val); | ||
435 | |||
436 | public abstract float GetContactProcessingThreshold(BulletBody obj); | ||
437 | |||
438 | public abstract bool IsStaticObject(BulletBody obj); | ||
439 | |||
440 | public abstract bool IsKinematicObject(BulletBody obj); | ||
441 | |||
442 | public abstract bool IsStaticOrKinematicObject(BulletBody obj); | ||
443 | |||
444 | public abstract bool HasContactResponse(BulletBody obj); | ||
445 | |||
446 | public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape); | ||
447 | |||
448 | public abstract BulletShape GetCollisionShape(BulletBody obj); | ||
449 | |||
450 | public abstract int GetActivationState(BulletBody obj); | ||
451 | |||
452 | public abstract void SetActivationState(BulletBody obj, int state); | ||
453 | |||
454 | public abstract void SetDeactivationTime(BulletBody obj, float dtime); | ||
455 | |||
456 | public abstract float GetDeactivationTime(BulletBody obj); | ||
457 | |||
458 | public abstract void ForceActivationState(BulletBody obj, ActivationState state); | ||
459 | |||
460 | public abstract void Activate(BulletBody obj, bool forceActivation); | ||
461 | |||
462 | public abstract bool IsActive(BulletBody obj); | ||
463 | |||
464 | public abstract void SetRestitution(BulletBody obj, float val); | ||
465 | |||
466 | public abstract float GetRestitution(BulletBody obj); | ||
467 | |||
468 | public abstract void SetFriction(BulletBody obj, float val); | ||
469 | |||
470 | public abstract float GetFriction(BulletBody obj); | ||
471 | |||
472 | public abstract Vector3 GetPosition(BulletBody obj); | ||
473 | |||
474 | public abstract Quaternion GetOrientation(BulletBody obj); | ||
475 | |||
476 | public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation); | ||
477 | |||
478 | // public abstract IntPtr GetBroadphaseHandle(BulletBody obj); | ||
479 | |||
480 | // public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle); | ||
481 | |||
482 | public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel); | ||
483 | |||
484 | public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel); | ||
485 | |||
486 | public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel); | ||
487 | |||
488 | public abstract float GetHitFraction(BulletBody obj); | ||
489 | |||
490 | public abstract void SetHitFraction(BulletBody obj, float val); | ||
491 | |||
492 | public abstract CollisionFlags GetCollisionFlags(BulletBody obj); | ||
493 | |||
494 | public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags); | ||
495 | |||
496 | public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags); | ||
497 | |||
498 | public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags); | ||
499 | |||
500 | public abstract float GetCcdMotionThreshold(BulletBody obj); | ||
501 | |||
502 | public abstract void SetCcdMotionThreshold(BulletBody obj, float val); | ||
503 | |||
504 | public abstract float GetCcdSweptSphereRadius(BulletBody obj); | ||
505 | |||
506 | public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val); | ||
507 | |||
508 | public abstract IntPtr GetUserPointer(BulletBody obj); | ||
509 | |||
510 | public abstract void SetUserPointer(BulletBody obj, IntPtr val); | ||
511 | |||
512 | // ===================================================================================== | ||
513 | // btRigidBody entries | ||
514 | public abstract void ApplyGravity(BulletBody obj); | ||
515 | |||
516 | public abstract void SetGravity(BulletBody obj, Vector3 val); | ||
517 | |||
518 | public abstract Vector3 GetGravity(BulletBody obj); | ||
519 | |||
520 | public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping); | ||
521 | |||
522 | public abstract void SetLinearDamping(BulletBody obj, float lin_damping); | ||
523 | |||
524 | public abstract void SetAngularDamping(BulletBody obj, float ang_damping); | ||
525 | |||
526 | public abstract float GetLinearDamping(BulletBody obj); | ||
527 | |||
528 | public abstract float GetAngularDamping(BulletBody obj); | ||
529 | |||
530 | public abstract float GetLinearSleepingThreshold(BulletBody obj); | ||
531 | |||
532 | public abstract void ApplyDamping(BulletBody obj, float timeStep); | ||
533 | |||
534 | public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia); | ||
535 | |||
536 | public abstract Vector3 GetLinearFactor(BulletBody obj); | ||
537 | |||
538 | public abstract void SetLinearFactor(BulletBody obj, Vector3 factor); | ||
539 | |||
540 | public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot); | ||
541 | |||
542 | // Add a force to the object as if its mass is one. | ||
543 | public abstract void ApplyCentralForce(BulletBody obj, Vector3 force); | ||
544 | |||
545 | // Set the force being applied to the object as if its mass is one. | ||
546 | public abstract void SetObjectForce(BulletBody obj, Vector3 force); | ||
547 | |||
548 | public abstract Vector3 GetTotalForce(BulletBody obj); | ||
549 | |||
550 | public abstract Vector3 GetTotalTorque(BulletBody obj); | ||
551 | |||
552 | public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj); | ||
553 | |||
554 | public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert); | ||
555 | |||
556 | public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold); | ||
557 | |||
558 | public abstract void ApplyTorque(BulletBody obj, Vector3 torque); | ||
559 | |||
560 | // Apply force at the given point. Will add torque to the object. | ||
561 | public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos); | ||
562 | |||
563 | // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. | ||
564 | public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp); | ||
565 | |||
566 | // Apply impulse to the object's torque. Force is scaled by object's mass. | ||
567 | public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp); | ||
568 | |||
569 | // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. | ||
570 | public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos); | ||
571 | |||
572 | public abstract void ClearForces(BulletBody obj); | ||
573 | |||
574 | public abstract void ClearAllForces(BulletBody obj); | ||
575 | |||
576 | public abstract void UpdateInertiaTensor(BulletBody obj); | ||
577 | |||
578 | public abstract Vector3 GetLinearVelocity(BulletBody obj); | ||
579 | |||
580 | public abstract Vector3 GetAngularVelocity(BulletBody obj); | ||
581 | |||
582 | public abstract void SetLinearVelocity(BulletBody obj, Vector3 val); | ||
583 | |||
584 | public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity); | ||
585 | |||
586 | public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos); | ||
587 | |||
588 | public abstract void Translate(BulletBody obj, Vector3 trans); | ||
589 | |||
590 | public abstract void UpdateDeactivation(BulletBody obj, float timeStep); | ||
591 | |||
592 | public abstract bool WantsSleeping(BulletBody obj); | ||
593 | |||
594 | public abstract void SetAngularFactor(BulletBody obj, float factor); | ||
595 | |||
596 | public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor); | ||
597 | |||
598 | public abstract Vector3 GetAngularFactor(BulletBody obj); | ||
599 | |||
600 | public abstract bool IsInWorld(BulletWorld world, BulletBody obj); | ||
601 | |||
602 | public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain); | ||
603 | |||
604 | public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain); | ||
605 | |||
606 | public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index); | ||
607 | |||
608 | public abstract int GetNumConstraintRefs(BulletBody obj); | ||
609 | |||
610 | public abstract bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask); | ||
611 | |||
612 | // ===================================================================================== | ||
613 | // btCollisionShape entries | ||
614 | |||
615 | public abstract float GetAngularMotionDisc(BulletShape shape); | ||
616 | |||
617 | public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor); | ||
618 | |||
619 | public abstract bool IsPolyhedral(BulletShape shape); | ||
620 | |||
621 | public abstract bool IsConvex2d(BulletShape shape); | ||
622 | |||
623 | public abstract bool IsConvex(BulletShape shape); | ||
624 | |||
625 | public abstract bool IsNonMoving(BulletShape shape); | ||
626 | |||
627 | public abstract bool IsConcave(BulletShape shape); | ||
628 | |||
629 | public abstract bool IsCompound(BulletShape shape); | ||
630 | |||
631 | public abstract bool IsSoftBody(BulletShape shape); | ||
632 | |||
633 | public abstract bool IsInfinite(BulletShape shape); | ||
634 | |||
635 | public abstract void SetLocalScaling(BulletShape shape, Vector3 scale); | ||
636 | |||
637 | public abstract Vector3 GetLocalScaling(BulletShape shape); | ||
638 | |||
639 | public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass); | ||
640 | |||
641 | public abstract int GetShapeType(BulletShape shape); | ||
642 | |||
643 | public abstract void SetMargin(BulletShape shape, float val); | ||
644 | |||
645 | public abstract float GetMargin(BulletShape shape); | ||
646 | |||
647 | // ===================================================================================== | ||
648 | // Debugging | ||
649 | public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { } | ||
650 | |||
651 | public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { } | ||
652 | |||
653 | public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { } | ||
654 | |||
655 | public virtual void DumpActivationInfo(BulletWorld sim) { } | ||
656 | |||
657 | public virtual void DumpAllInfo(BulletWorld sim) { } | ||
658 | |||
659 | public virtual void DumpPhysicsStatistics(BulletWorld sim) { } | ||
660 | |||
661 | public virtual void ResetBroadphasePool(BulletWorld sim) { } | ||
662 | |||
663 | public virtual void ResetConstraintSolver(BulletWorld sim) { } | ||
664 | |||
665 | }; | ||
666 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 4c195e1..c215e3a 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -66,9 +66,10 @@ public sealed class BSCharacter : BSPhysObject | |||
66 | private float _buoyancy; | 66 | private float _buoyancy; |
67 | 67 | ||
68 | // The friction and velocity of the avatar is modified depending on whether walking or not. | 68 | // The friction and velocity of the avatar is modified depending on whether walking or not. |
69 | private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar | ||
70 | private float _currentFriction; // the friction currently being used (changed by setVelocity). | 69 | private float _currentFriction; // the friction currently being used (changed by setVelocity). |
71 | 70 | ||
71 | private BSVMotor _velocityMotor; | ||
72 | |||
72 | private OMV.Vector3 _PIDTarget; | 73 | private OMV.Vector3 _PIDTarget; |
73 | private bool _usePID; | 74 | private bool _usePID; |
74 | private float _PIDTau; | 75 | private float _PIDTau; |
@@ -83,34 +84,36 @@ public sealed class BSCharacter : BSPhysObject | |||
83 | _physicsActorType = (int)ActorTypes.Agent; | 84 | _physicsActorType = (int)ActorTypes.Agent; |
84 | _position = pos; | 85 | _position = pos; |
85 | 86 | ||
86 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||
87 | // replace with the default values. | ||
88 | _size = size; | ||
89 | if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth; | ||
90 | if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth; | ||
91 | |||
92 | _flying = isFlying; | 87 | _flying = isFlying; |
93 | _orientation = OMV.Quaternion.Identity; | 88 | _orientation = OMV.Quaternion.Identity; |
94 | _velocity = OMV.Vector3.Zero; | 89 | _velocity = OMV.Vector3.Zero; |
95 | _appliedVelocity = OMV.Vector3.Zero; | ||
96 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); | 90 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); |
97 | _currentFriction = PhysicsScene.Params.avatarStandingFriction; | 91 | _currentFriction = BSParam.AvatarStandingFriction; |
98 | _avatarDensity = PhysicsScene.Params.avatarDensity; | 92 | _avatarDensity = BSParam.AvatarDensity; |
99 | 93 | ||
100 | // The dimensions of the avatar capsule are kept in the scale. | 94 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, |
95 | // replace with the default values. | ||
96 | _size = size; | ||
97 | if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; | ||
98 | if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; | ||
99 | |||
100 | // The dimensions of the physical capsule are kept in the scale. | ||
101 | // Physics creates a unit capsule which is scaled by the physics engine. | 101 | // Physics creates a unit capsule which is scaled by the physics engine. |
102 | ComputeAvatarScale(_size); | 102 | Scale = ComputeAvatarScale(_size); |
103 | // set _avatarVolume and _mass based on capsule size, _density and Scale | 103 | // set _avatarVolume and _mass based on capsule size, _density and Scale |
104 | ComputeAvatarVolumeAndMass(); | 104 | ComputeAvatarVolumeAndMass(); |
105 | |||
106 | SetupMovementMotor(); | ||
107 | |||
105 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | 108 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", |
106 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | 109 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); |
107 | 110 | ||
108 | // do actual create at taint time | 111 | // do actual creation in taint time |
109 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | 112 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() |
110 | { | 113 | { |
111 | DetailLog("{0},BSCharacter.create,taint", LocalID); | 114 | DetailLog("{0},BSCharacter.create,taint", LocalID); |
112 | // New body and shape into PhysBody and PhysShape | 115 | // New body and shape into PhysBody and PhysShape |
113 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); | 116 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); |
114 | 117 | ||
115 | SetPhysicalProperties(); | 118 | SetPhysicalProperties(); |
116 | }); | 119 | }); |
@@ -120,54 +123,116 @@ public sealed class BSCharacter : BSPhysObject | |||
120 | // called when this character is being destroyed and the resources should be released | 123 | // called when this character is being destroyed and the resources should be released |
121 | public override void Destroy() | 124 | public override void Destroy() |
122 | { | 125 | { |
126 | base.Destroy(); | ||
127 | |||
123 | DetailLog("{0},BSCharacter.Destroy", LocalID); | 128 | DetailLog("{0},BSCharacter.Destroy", LocalID); |
124 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | 129 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() |
125 | { | 130 | { |
126 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | 131 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); |
132 | PhysBody.Clear(); | ||
127 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | 133 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); |
134 | PhysShape.Clear(); | ||
128 | }); | 135 | }); |
129 | } | 136 | } |
130 | 137 | ||
131 | private void SetPhysicalProperties() | 138 | private void SetPhysicalProperties() |
132 | { | 139 | { |
133 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | 140 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); |
134 | 141 | ||
135 | ZeroMotion(true); | 142 | ZeroMotion(true); |
136 | ForcePosition = _position; | 143 | ForcePosition = _position; |
144 | |||
137 | // Set the velocity and compute the proper friction | 145 | // Set the velocity and compute the proper friction |
146 | _velocityMotor.Reset(); | ||
147 | _velocityMotor.SetTarget(_velocity); | ||
148 | _velocityMotor.SetCurrent(_velocity); | ||
138 | ForceVelocity = _velocity; | 149 | ForceVelocity = _velocity; |
139 | 150 | ||
140 | // This will enable or disable the flying buoyancy of the avatar. | 151 | // This will enable or disable the flying buoyancy of the avatar. |
141 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. | 152 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. |
142 | Flying = _flying; | 153 | Flying = _flying; |
143 | 154 | ||
144 | BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution); | 155 | PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); |
145 | BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); | 156 | PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); |
146 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | 157 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); |
147 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); | 158 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
148 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | 159 | if (BSParam.CcdMotionThreshold > 0f) |
149 | { | 160 | { |
150 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | 161 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
151 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | 162 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
152 | } | 163 | } |
153 | 164 | ||
154 | UpdatePhysicalMassProperties(RawMass); | 165 | UpdatePhysicalMassProperties(RawMass, false); |
155 | 166 | ||
156 | // Make so capsule does not fall over | 167 | // Make so capsule does not fall over |
157 | BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero); | 168 | PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); |
158 | 169 | ||
159 | BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); | 170 | PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); |
160 | 171 | ||
161 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | 172 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); |
162 | 173 | ||
163 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); | 174 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); |
164 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION); | 175 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); |
165 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | 176 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); |
166 | 177 | ||
167 | // Do this after the object has been added to the world | 178 | // Do this after the object has been added to the world |
168 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, | 179 | PhysBody.collisionType = CollisionType.Avatar; |
169 | (uint)CollisionFilterGroups.AvatarFilter, | 180 | PhysBody.ApplyCollisionMask(PhysicsScene); |
170 | (uint)CollisionFilterGroups.AvatarMask); | 181 | } |
182 | |||
183 | // The avatar's movement is controlled by this motor that speeds up and slows down | ||
184 | // the avatar seeking to reach the motor's target speed. | ||
185 | // This motor runs as a prestep action for the avatar so it will keep the avatar | ||
186 | // standing as well as moving. Destruction of the avatar will destroy the pre-step action. | ||
187 | private void SetupMovementMotor() | ||
188 | { | ||
189 | |||
190 | // Someday, use a PID motor for asymmetric speed up and slow down | ||
191 | // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); | ||
192 | |||
193 | // Infinite decay and timescale values so motor only changes current to target values. | ||
194 | _velocityMotor = new BSVMotor("BSCharacter.Velocity", | ||
195 | 0.2f, // time scale | ||
196 | BSMotor.Infinite, // decay time scale | ||
197 | BSMotor.InfiniteVector, // friction timescale | ||
198 | 1f // efficiency | ||
199 | ); | ||
200 | // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
201 | |||
202 | RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep) | ||
203 | { | ||
204 | // TODO: Decide if the step parameters should be changed depending on the avatar's | ||
205 | // state (flying, colliding, ...). There is code in ODE to do this. | ||
206 | |||
207 | OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep); | ||
208 | |||
209 | // If falling, we keep the world's downward vector no matter what the other axis specify. | ||
210 | if (!Flying && !IsColliding) | ||
211 | { | ||
212 | stepVelocity.Z = _velocity.Z; | ||
213 | // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||
214 | } | ||
215 | |||
216 | // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. | ||
217 | OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass; | ||
218 | |||
219 | /* | ||
220 | // If moveForce is very small, zero things so we don't keep sending microscopic updates to the user | ||
221 | float moveForceMagnitudeSquared = moveForce.LengthSquared(); | ||
222 | if (moveForceMagnitudeSquared < 0.0001) | ||
223 | { | ||
224 | DetailLog("{0},BSCharacter.MoveMotor,zeroMovement,stepVel={1},vel={2},mass={3},magSq={4},moveForce={5}", | ||
225 | LocalID, stepVelocity, _velocity, Mass, moveForceMagnitudeSquared, moveForce); | ||
226 | ForceVelocity = OMV.Vector3.Zero; | ||
227 | } | ||
228 | else | ||
229 | { | ||
230 | AddForce(moveForce, false, true); | ||
231 | } | ||
232 | */ | ||
233 | // DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce); | ||
234 | PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce); | ||
235 | }); | ||
171 | } | 236 | } |
172 | 237 | ||
173 | public override void RequestPhysicsterseUpdate() | 238 | public override void RequestPhysicsterseUpdate() |
@@ -185,24 +250,31 @@ public sealed class BSCharacter : BSPhysObject | |||
185 | } | 250 | } |
186 | 251 | ||
187 | set { | 252 | set { |
188 | // When an avatar's size is set, only the height is changed. | ||
189 | _size = value; | 253 | _size = value; |
190 | ComputeAvatarScale(_size); | 254 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, |
255 | // replace with the default values. | ||
256 | if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; | ||
257 | if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; | ||
258 | |||
259 | Scale = ComputeAvatarScale(_size); | ||
191 | ComputeAvatarVolumeAndMass(); | 260 | ComputeAvatarVolumeAndMass(); |
192 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", | 261 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", |
193 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | 262 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); |
194 | 263 | ||
195 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | 264 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() |
196 | { | 265 | { |
197 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | 266 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) |
198 | UpdatePhysicalMassProperties(RawMass); | 267 | { |
268 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); | ||
269 | UpdatePhysicalMassProperties(RawMass, true); | ||
270 | // Make sure this change appears as a property update event | ||
271 | PhysicsScene.PE.PushUpdate(PhysBody); | ||
272 | } | ||
199 | }); | 273 | }); |
200 | 274 | ||
201 | } | 275 | } |
202 | } | 276 | } |
203 | 277 | ||
204 | public override OMV.Vector3 Scale { get; set; } | ||
205 | |||
206 | public override PrimitiveBaseShape Shape | 278 | public override PrimitiveBaseShape Shape |
207 | { | 279 | { |
208 | set { BaseShape = value; } | 280 | set { BaseShape = value; } |
@@ -236,7 +308,8 @@ public sealed class BSCharacter : BSPhysObject | |||
236 | // Zero some other properties directly into the physics engine | 308 | // Zero some other properties directly into the physics engine |
237 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 309 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
238 | { | 310 | { |
239 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | 311 | if (PhysBody.HasPhysicalBody) |
312 | PhysicsScene.PE.ClearAllForces(PhysBody); | ||
240 | }); | 313 | }); |
241 | } | 314 | } |
242 | public override void ZeroAngularMotion(bool inTaintTime) | 315 | public override void ZeroAngularMotion(bool inTaintTime) |
@@ -245,10 +318,13 @@ public sealed class BSCharacter : BSPhysObject | |||
245 | 318 | ||
246 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 319 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
247 | { | 320 | { |
248 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 321 | if (PhysBody.HasPhysicalBody) |
249 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 322 | { |
250 | // The next also get rid of applied linear force but the linear velocity is untouched. | 323 | PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); |
251 | BulletSimAPI.ClearForces2(PhysBody.ptr); | 324 | PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); |
325 | // The next also get rid of applied linear force but the linear velocity is untouched. | ||
326 | PhysicsScene.PE.ClearForces(PhysBody); | ||
327 | } | ||
252 | }); | 328 | }); |
253 | } | 329 | } |
254 | 330 | ||
@@ -263,7 +339,7 @@ public sealed class BSCharacter : BSPhysObject | |||
263 | public override OMV.Vector3 Position { | 339 | public override OMV.Vector3 Position { |
264 | get { | 340 | get { |
265 | // Don't refetch the position because this function is called a zillion times | 341 | // Don't refetch the position because this function is called a zillion times |
266 | // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); | 342 | // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); |
267 | return _position; | 343 | return _position; |
268 | } | 344 | } |
269 | set { | 345 | set { |
@@ -273,19 +349,20 @@ public sealed class BSCharacter : BSPhysObject | |||
273 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | 349 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() |
274 | { | 350 | { |
275 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 351 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
276 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 352 | if (PhysBody.HasPhysicalBody) |
353 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
277 | }); | 354 | }); |
278 | } | 355 | } |
279 | } | 356 | } |
280 | public override OMV.Vector3 ForcePosition { | 357 | public override OMV.Vector3 ForcePosition { |
281 | get { | 358 | get { |
282 | _position = BulletSimAPI.GetPosition2(PhysBody.ptr); | 359 | _position = PhysicsScene.PE.GetPosition(PhysBody); |
283 | return _position; | 360 | return _position; |
284 | } | 361 | } |
285 | set { | 362 | set { |
286 | _position = value; | 363 | _position = value; |
287 | PositionSanityCheck(); | 364 | PositionSanityCheck(); |
288 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 365 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); |
289 | } | 366 | } |
290 | } | 367 | } |
291 | 368 | ||
@@ -297,6 +374,15 @@ public sealed class BSCharacter : BSPhysObject | |||
297 | { | 374 | { |
298 | bool ret = false; | 375 | bool ret = false; |
299 | 376 | ||
377 | // TODO: check for out of bounds | ||
378 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) | ||
379 | { | ||
380 | // The character is out of the known/simulated area. | ||
381 | // Upper levels of code will handle the transition to other areas so, for | ||
382 | // the time, we just ignore the position. | ||
383 | return ret; | ||
384 | } | ||
385 | |||
300 | // If below the ground, move the avatar up | 386 | // If below the ground, move the avatar up |
301 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | 387 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); |
302 | if (Position.Z < terrainHeight) | 388 | if (Position.Z < terrainHeight) |
@@ -307,7 +393,7 @@ public sealed class BSCharacter : BSPhysObject | |||
307 | } | 393 | } |
308 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 394 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
309 | { | 395 | { |
310 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | 396 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
311 | if (Position.Z < waterHeight) | 397 | if (Position.Z < waterHeight) |
312 | { | 398 | { |
313 | _position.Z = waterHeight; | 399 | _position.Z = waterHeight; |
@@ -315,7 +401,6 @@ public sealed class BSCharacter : BSPhysObject | |||
315 | } | 401 | } |
316 | } | 402 | } |
317 | 403 | ||
318 | // TODO: check for out of bounds | ||
319 | return ret; | 404 | return ret; |
320 | } | 405 | } |
321 | 406 | ||
@@ -332,7 +417,8 @@ public sealed class BSCharacter : BSPhysObject | |||
332 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() | 417 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() |
333 | { | 418 | { |
334 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 419 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
335 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 420 | if (PhysBody.HasPhysicalBody) |
421 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
336 | }); | 422 | }); |
337 | ret = true; | 423 | ret = true; |
338 | } | 424 | } |
@@ -345,10 +431,10 @@ public sealed class BSCharacter : BSPhysObject | |||
345 | public override float RawMass { | 431 | public override float RawMass { |
346 | get {return _mass; } | 432 | get {return _mass; } |
347 | } | 433 | } |
348 | public override void UpdatePhysicalMassProperties(float physMass) | 434 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) |
349 | { | 435 | { |
350 | OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); | 436 | OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); |
351 | BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); | 437 | PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); |
352 | } | 438 | } |
353 | 439 | ||
354 | public override OMV.Vector3 Force { | 440 | public override OMV.Vector3 Force { |
@@ -359,7 +445,8 @@ public sealed class BSCharacter : BSPhysObject | |||
359 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | 445 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() |
360 | { | 446 | { |
361 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | 447 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); |
362 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 448 | if (PhysBody.HasPhysicalBody) |
449 | PhysicsScene.PE.SetObjectForce(PhysBody, _force); | ||
363 | }); | 450 | }); |
364 | } | 451 | } |
365 | } | 452 | } |
@@ -376,6 +463,31 @@ public sealed class BSCharacter : BSPhysObject | |||
376 | 463 | ||
377 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } | 464 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } |
378 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } | 465 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } |
466 | |||
467 | // Sets the target in the motor. This starts the changing of the avatar's velocity. | ||
468 | public override OMV.Vector3 TargetVelocity | ||
469 | { | ||
470 | get | ||
471 | { | ||
472 | return _velocityMotor.TargetValue; | ||
473 | } | ||
474 | set | ||
475 | { | ||
476 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); | ||
477 | OMV.Vector3 targetVel = value; | ||
478 | if (_setAlwaysRun) | ||
479 | targetVel *= BSParam.AvatarAlwaysRunFactor; | ||
480 | |||
481 | PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() | ||
482 | { | ||
483 | _velocityMotor.Reset(); | ||
484 | _velocityMotor.SetTarget(targetVel); | ||
485 | _velocityMotor.SetCurrent(_velocity); | ||
486 | _velocityMotor.Enabled = true; | ||
487 | }); | ||
488 | } | ||
489 | } | ||
490 | // Directly setting velocity means this is what the user really wants now. | ||
379 | public override OMV.Vector3 Velocity { | 491 | public override OMV.Vector3 Velocity { |
380 | get { return _velocity; } | 492 | get { return _velocity; } |
381 | set { | 493 | set { |
@@ -383,6 +495,12 @@ public sealed class BSCharacter : BSPhysObject | |||
383 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); | 495 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); |
384 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() | 496 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() |
385 | { | 497 | { |
498 | _velocityMotor.Reset(); | ||
499 | _velocityMotor.SetCurrent(_velocity); | ||
500 | _velocityMotor.SetTarget(_velocity); | ||
501 | // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar. | ||
502 | _velocityMotor.Enabled = false; | ||
503 | |||
386 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); | 504 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); |
387 | ForceVelocity = _velocity; | 505 | ForceVelocity = _velocity; |
388 | }); | 506 | }); |
@@ -391,30 +509,32 @@ public sealed class BSCharacter : BSPhysObject | |||
391 | public override OMV.Vector3 ForceVelocity { | 509 | public override OMV.Vector3 ForceVelocity { |
392 | get { return _velocity; } | 510 | get { return _velocity; } |
393 | set { | 511 | set { |
512 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); | ||
513 | |||
514 | _velocity = value; | ||
394 | // Depending on whether the avatar is moving or not, change the friction | 515 | // Depending on whether the avatar is moving or not, change the friction |
395 | // to keep the avatar from slipping around | 516 | // to keep the avatar from slipping around |
396 | if (_velocity.Length() == 0) | 517 | if (_velocity.Length() == 0) |
397 | { | 518 | { |
398 | if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) | 519 | if (_currentFriction != BSParam.AvatarStandingFriction) |
399 | { | 520 | { |
400 | _currentFriction = PhysicsScene.Params.avatarStandingFriction; | 521 | _currentFriction = BSParam.AvatarStandingFriction; |
401 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | 522 | if (PhysBody.HasPhysicalBody) |
523 | PhysicsScene.PE.SetFriction(PhysBody, _currentFriction); | ||
402 | } | 524 | } |
403 | } | 525 | } |
404 | else | 526 | else |
405 | { | 527 | { |
406 | if (_currentFriction != PhysicsScene.Params.avatarFriction) | 528 | if (_currentFriction != BSParam.AvatarFriction) |
407 | { | 529 | { |
408 | _currentFriction = PhysicsScene.Params.avatarFriction; | 530 | _currentFriction = BSParam.AvatarFriction; |
409 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | 531 | if (PhysBody.HasPhysicalBody) |
532 | PhysicsScene.PE.SetFriction(PhysBody, _currentFriction); | ||
410 | } | 533 | } |
411 | } | 534 | } |
412 | _velocity = value; | ||
413 | // Remember the set velocity so we can suppress the reduction by friction, ... | ||
414 | _appliedVelocity = value; | ||
415 | 535 | ||
416 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | 536 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); |
417 | BulletSimAPI.Activate2(PhysBody.ptr, true); | 537 | PhysicsScene.PE.Activate(PhysBody, true); |
418 | } | 538 | } |
419 | } | 539 | } |
420 | public override OMV.Vector3 Torque { | 540 | public override OMV.Vector3 Torque { |
@@ -439,13 +559,16 @@ public sealed class BSCharacter : BSPhysObject | |||
439 | public override OMV.Quaternion Orientation { | 559 | public override OMV.Quaternion Orientation { |
440 | get { return _orientation; } | 560 | get { return _orientation; } |
441 | set { | 561 | set { |
442 | _orientation = value; | 562 | // Orientation is set zillions of times when an avatar is walking. It's like |
443 | // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); | 563 | // the viewer doesn't trust us. |
444 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | 564 | if (_orientation != value) |
445 | { | 565 | { |
446 | // _position = BulletSimAPI.GetPosition2(BSBody.ptr); | 566 | _orientation = value; |
447 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 567 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() |
448 | }); | 568 | { |
569 | ForceOrientation = _orientation; | ||
570 | }); | ||
571 | } | ||
449 | } | 572 | } |
450 | } | 573 | } |
451 | // Go directly to Bullet to get/set the value. | 574 | // Go directly to Bullet to get/set the value. |
@@ -453,13 +576,17 @@ public sealed class BSCharacter : BSPhysObject | |||
453 | { | 576 | { |
454 | get | 577 | get |
455 | { | 578 | { |
456 | _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); | 579 | _orientation = PhysicsScene.PE.GetOrientation(PhysBody); |
457 | return _orientation; | 580 | return _orientation; |
458 | } | 581 | } |
459 | set | 582 | set |
460 | { | 583 | { |
461 | _orientation = value; | 584 | _orientation = value; |
462 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 585 | if (PhysBody.HasPhysicalBody) |
586 | { | ||
587 | // _position = PhysicsScene.PE.GetPosition(BSBody); | ||
588 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
589 | } | ||
463 | } | 590 | } |
464 | } | 591 | } |
465 | public override int PhysicsActorType { | 592 | public override int PhysicsActorType { |
@@ -482,6 +609,7 @@ public sealed class BSCharacter : BSPhysObject | |||
482 | get { return _flying; } | 609 | get { return _flying; } |
483 | set { | 610 | set { |
484 | _flying = value; | 611 | _flying = value; |
612 | |||
485 | // simulate flying by changing the effect of gravity | 613 | // simulate flying by changing the effect of gravity |
486 | Buoyancy = ComputeBuoyancyFromFlying(_flying); | 614 | Buoyancy = ComputeBuoyancyFromFlying(_flying); |
487 | } | 615 | } |
@@ -500,27 +628,18 @@ public sealed class BSCharacter : BSPhysObject | |||
500 | get { return _throttleUpdates; } | 628 | get { return _throttleUpdates; } |
501 | set { _throttleUpdates = value; } | 629 | set { _throttleUpdates = value; } |
502 | } | 630 | } |
503 | public override bool IsColliding { | ||
504 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | ||
505 | set { _isColliding = value; } | ||
506 | } | ||
507 | public override bool CollidingGround { | ||
508 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | ||
509 | set { CollidingGround = value; } | ||
510 | } | ||
511 | public override bool CollidingObj { | ||
512 | get { return _collidingObj; } | ||
513 | set { _collidingObj = value; } | ||
514 | } | ||
515 | public override bool FloatOnWater { | 631 | public override bool FloatOnWater { |
516 | set { | 632 | set { |
517 | _floatOnWater = value; | 633 | _floatOnWater = value; |
518 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() | 634 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() |
519 | { | 635 | { |
520 | if (_floatOnWater) | 636 | if (PhysBody.HasPhysicalBody) |
521 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 637 | { |
522 | else | 638 | if (_floatOnWater) |
523 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 639 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
640 | else | ||
641 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | ||
642 | } | ||
524 | }); | 643 | }); |
525 | } | 644 | } |
526 | } | 645 | } |
@@ -549,11 +668,15 @@ public sealed class BSCharacter : BSPhysObject | |||
549 | } | 668 | } |
550 | public override float ForceBuoyancy { | 669 | public override float ForceBuoyancy { |
551 | get { return _buoyancy; } | 670 | get { return _buoyancy; } |
552 | set { _buoyancy = value; | 671 | set { |
672 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); | ||
673 | |||
674 | _buoyancy = value; | ||
553 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 675 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
554 | // Buoyancy is faked by changing the gravity applied to the object | 676 | // Buoyancy is faked by changing the gravity applied to the object |
555 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | 677 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); |
556 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | 678 | if (PhysBody.HasPhysicalBody) |
679 | PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav)); | ||
557 | } | 680 | } |
558 | } | 681 | } |
559 | 682 | ||
@@ -589,24 +712,40 @@ public sealed class BSCharacter : BSPhysObject | |||
589 | public override float APIDStrength { set { return; } } | 712 | public override float APIDStrength { set { return; } } |
590 | public override float APIDDamping { set { return; } } | 713 | public override float APIDDamping { set { return; } } |
591 | 714 | ||
592 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 715 | public override void AddForce(OMV.Vector3 force, bool pushforce) |
716 | { | ||
717 | // Since this force is being applied in only one step, make this a force per second. | ||
718 | OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; | ||
719 | AddForce(addForce, pushforce, false); | ||
720 | } | ||
721 | private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | ||
593 | if (force.IsFinite()) | 722 | if (force.IsFinite()) |
594 | { | 723 | { |
595 | _force.X += force.X; | 724 | float magnitude = force.Length(); |
596 | _force.Y += force.Y; | 725 | if (magnitude > BSParam.MaxAddForceMagnitude) |
597 | _force.Z += force.Z; | ||
598 | // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); | ||
599 | PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() | ||
600 | { | 726 | { |
601 | DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); | 727 | // Force has a limit |
602 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 728 | force = force / magnitude * BSParam.MaxAddForceMagnitude; |
729 | } | ||
730 | |||
731 | OMV.Vector3 addForce = force; | ||
732 | // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); | ||
733 | |||
734 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() | ||
735 | { | ||
736 | // Bullet adds this central force to the total force for this tick | ||
737 | // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); | ||
738 | if (PhysBody.HasPhysicalBody) | ||
739 | { | ||
740 | PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); | ||
741 | } | ||
603 | }); | 742 | }); |
604 | } | 743 | } |
605 | else | 744 | else |
606 | { | 745 | { |
607 | m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader); | 746 | m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID); |
747 | return; | ||
608 | } | 748 | } |
609 | //m_lastUpdateSent = false; | ||
610 | } | 749 | } |
611 | 750 | ||
612 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 751 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { |
@@ -614,24 +753,31 @@ public sealed class BSCharacter : BSPhysObject | |||
614 | public override void SetMomentum(OMV.Vector3 momentum) { | 753 | public override void SetMomentum(OMV.Vector3 momentum) { |
615 | } | 754 | } |
616 | 755 | ||
617 | private void ComputeAvatarScale(OMV.Vector3 size) | 756 | private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) |
618 | { | 757 | { |
619 | // The 'size' given by the simulator is the mid-point of the avatar | 758 | OMV.Vector3 newScale; |
620 | // and X and Y are unspecified. | 759 | |
621 | 760 | // Bullet's capsule total height is the "passed height + radius * 2"; | |
622 | OMV.Vector3 newScale = size; | 761 | // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) |
623 | // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; | 762 | // The number we pass in for 'scaling' is the multiplier to get that base |
624 | // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; | 763 | // shape to be the size desired. |
625 | 764 | // So, when creating the scale for the avatar height, we take the passed height | |
626 | // From the total height, remove the capsule half spheres that are at each end | 765 | // (size.Z) and remove the caps. |
627 | // The 1.15f came from ODE. Not sure what this factors in. | 766 | // Another oddity of the Bullet capsule implementation is that it presumes the Y |
628 | // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y); | 767 | // dimension is the radius of the capsule. Even though some of the code allows |
768 | // for a asymmetrical capsule, other parts of the code presume it is cylindrical. | ||
769 | |||
770 | // Scale is multiplier of radius with one of "0.5" | ||
771 | newScale.X = size.X / 2f; | ||
772 | newScale.Y = size.Y / 2f; | ||
629 | 773 | ||
630 | // The total scale height is the central cylindar plus the caps on the two ends. | 774 | // The total scale height is the central cylindar plus the caps on the two ends. |
631 | newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f); | 775 | newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f; |
776 | // If smaller than the endcaps, just fake like we're almost that small | ||
777 | if (newScale.Z < 0) | ||
778 | newScale.Z = 0.1f; | ||
632 | 779 | ||
633 | // Convert diameters to radii and height to half height -- the way Bullet expects it. | 780 | return newScale; |
634 | Scale = newScale / 2f; | ||
635 | } | 781 | } |
636 | 782 | ||
637 | // set _avatarVolume and _mass based on capsule size, _density and Scale | 783 | // set _avatarVolume and _mass based on capsule size, _density and Scale |
@@ -639,14 +785,14 @@ public sealed class BSCharacter : BSPhysObject | |||
639 | { | 785 | { |
640 | _avatarVolume = (float)( | 786 | _avatarVolume = (float)( |
641 | Math.PI | 787 | Math.PI |
642 | * Scale.X | 788 | * Size.X / 2f |
643 | * Scale.Y // the area of capsule cylinder | 789 | * Size.Y / 2f // the area of capsule cylinder |
644 | * Scale.Z // times height of capsule cylinder | 790 | * Size.Z // times height of capsule cylinder |
645 | + 1.33333333f | 791 | + 1.33333333f |
646 | * Math.PI | 792 | * Math.PI |
647 | * Scale.X | 793 | * Size.X / 2f |
648 | * Math.Min(Scale.X, Scale.Y) | 794 | * Math.Min(Size.X, Size.Y) / 2 |
649 | * Scale.Y // plus the volume of the capsule end caps | 795 | * Size.Y / 2f // plus the volume of the capsule end caps |
650 | ); | 796 | ); |
651 | _mass = _avatarDensity * _avatarVolume; | 797 | _mass = _avatarDensity * _avatarVolume; |
652 | } | 798 | } |
@@ -660,6 +806,7 @@ public sealed class BSCharacter : BSPhysObject | |||
660 | _velocity = entprop.Velocity; | 806 | _velocity = entprop.Velocity; |
661 | _acceleration = entprop.Acceleration; | 807 | _acceleration = entprop.Acceleration; |
662 | _rotationalVelocity = entprop.RotationalVelocity; | 808 | _rotationalVelocity = entprop.RotationalVelocity; |
809 | |||
663 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. | 810 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. |
664 | PositionSanityCheck(true); | 811 | PositionSanityCheck(true); |
665 | 812 | ||
@@ -667,17 +814,8 @@ public sealed class BSCharacter : BSPhysObject | |||
667 | LastEntityProperties = CurrentEntityProperties; | 814 | LastEntityProperties = CurrentEntityProperties; |
668 | CurrentEntityProperties = entprop; | 815 | CurrentEntityProperties = entprop; |
669 | 816 | ||
670 | if (entprop.Velocity != LastEntityProperties.Velocity) | ||
671 | { | ||
672 | // Changes in the velocity are suppressed in avatars. | ||
673 | // That's just the way they are defined. | ||
674 | OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z); | ||
675 | _velocity = avVel; | ||
676 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel); | ||
677 | } | ||
678 | |||
679 | // Tell the linkset about value changes | 817 | // Tell the linkset about value changes |
680 | Linkset.UpdateProperties(this); | 818 | Linkset.UpdateProperties(this, true); |
681 | 819 | ||
682 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. | 820 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. |
683 | // base.RequestPhysicsterseUpdate(); | 821 | // base.RequestPhysicsterseUpdate(); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs index 65fac00..b813974 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs | |||
@@ -36,7 +36,8 @@ public abstract class BSConstraint : IDisposable | |||
36 | { | 36 | { |
37 | private static string LogHeader = "[BULLETSIM CONSTRAINT]"; | 37 | private static string LogHeader = "[BULLETSIM CONSTRAINT]"; |
38 | 38 | ||
39 | protected BulletSim m_world; | 39 | protected BulletWorld m_world; |
40 | protected BSScene PhysicsScene; | ||
40 | protected BulletBody m_body1; | 41 | protected BulletBody m_body1; |
41 | protected BulletBody m_body2; | 42 | protected BulletBody m_body2; |
42 | protected BulletConstraint m_constraint; | 43 | protected BulletConstraint m_constraint; |
@@ -48,8 +49,10 @@ public abstract class BSConstraint : IDisposable | |||
48 | public abstract ConstraintType Type { get; } | 49 | public abstract ConstraintType Type { get; } |
49 | public bool IsEnabled { get { return m_enabled; } } | 50 | public bool IsEnabled { get { return m_enabled; } } |
50 | 51 | ||
51 | public BSConstraint() | 52 | public BSConstraint(BulletWorld world) |
52 | { | 53 | { |
54 | m_world = world; | ||
55 | PhysicsScene = m_world.physicsScene; | ||
53 | } | 56 | } |
54 | 57 | ||
55 | public virtual void Dispose() | 58 | public virtual void Dispose() |
@@ -57,15 +60,15 @@ public abstract class BSConstraint : IDisposable | |||
57 | if (m_enabled) | 60 | if (m_enabled) |
58 | { | 61 | { |
59 | m_enabled = false; | 62 | m_enabled = false; |
60 | if (m_constraint.ptr != IntPtr.Zero) | 63 | if (m_constraint.HasPhysicalConstraint) |
61 | { | 64 | { |
62 | bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); | 65 | bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint); |
63 | m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", | 66 | m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", |
64 | BSScene.DetailLogZero, | 67 | BSScene.DetailLogZero, |
65 | m_body1.ID, m_body1.ptr.ToString("X"), | 68 | m_body1.ID, m_body1.AddrString, |
66 | m_body2.ID, m_body2.ptr.ToString("X"), | 69 | m_body2.ID, m_body2.AddrString, |
67 | success); | 70 | success); |
68 | m_constraint.ptr = System.IntPtr.Zero; | 71 | m_constraint.Clear(); |
69 | } | 72 | } |
70 | } | 73 | } |
71 | } | 74 | } |
@@ -74,7 +77,7 @@ public abstract class BSConstraint : IDisposable | |||
74 | { | 77 | { |
75 | bool ret = false; | 78 | bool ret = false; |
76 | if (m_enabled) | 79 | if (m_enabled) |
77 | ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high); | 80 | ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high); |
78 | return ret; | 81 | return ret; |
79 | } | 82 | } |
80 | 83 | ||
@@ -82,7 +85,7 @@ public abstract class BSConstraint : IDisposable | |||
82 | { | 85 | { |
83 | bool ret = false; | 86 | bool ret = false; |
84 | if (m_enabled) | 87 | if (m_enabled) |
85 | ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high); | 88 | ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); |
86 | return ret; | 89 | return ret; |
87 | } | 90 | } |
88 | 91 | ||
@@ -91,7 +94,7 @@ public abstract class BSConstraint : IDisposable | |||
91 | bool ret = false; | 94 | bool ret = false; |
92 | if (m_enabled) | 95 | if (m_enabled) |
93 | { | 96 | { |
94 | BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt); | 97 | PhysicsScene.PE.SetConstraintNumSolverIterations(m_constraint, cnt); |
95 | ret = true; | 98 | ret = true; |
96 | } | 99 | } |
97 | return ret; | 100 | return ret; |
@@ -103,7 +106,7 @@ public abstract class BSConstraint : IDisposable | |||
103 | if (m_enabled) | 106 | if (m_enabled) |
104 | { | 107 | { |
105 | // Recompute the internal transforms | 108 | // Recompute the internal transforms |
106 | BulletSimAPI.CalculateTransforms2(m_constraint.ptr); | 109 | PhysicsScene.PE.CalculateTransforms(m_constraint); |
107 | ret = true; | 110 | ret = true; |
108 | } | 111 | } |
109 | return ret; | 112 | return ret; |
@@ -122,7 +125,7 @@ public abstract class BSConstraint : IDisposable | |||
122 | // Setting an object's mass to zero (making it static like when it's selected) | 125 | // Setting an object's mass to zero (making it static like when it's selected) |
123 | // automatically disables the constraints. | 126 | // automatically disables the constraints. |
124 | // If the link is enabled, be sure to set the constraint itself to enabled. | 127 | // If the link is enabled, be sure to set the constraint itself to enabled. |
125 | BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true)); | 128 | PhysicsScene.PE.SetConstraintEnable(m_constraint, BSParam.NumericBool(true)); |
126 | } | 129 | } |
127 | else | 130 | else |
128 | { | 131 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs index 23ef052..ecb1b32 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs | |||
@@ -39,51 +39,49 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
39 | public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } | 39 | public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } |
40 | 40 | ||
41 | // Create a btGeneric6DofConstraint | 41 | // Create a btGeneric6DofConstraint |
42 | public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2, | 42 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, |
43 | Vector3 frame1, Quaternion frame1rot, | 43 | Vector3 frame1, Quaternion frame1rot, |
44 | Vector3 frame2, Quaternion frame2rot, | 44 | Vector3 frame2, Quaternion frame2rot, |
45 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | 45 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) |
46 | : base(world) | ||
46 | { | 47 | { |
47 | m_world = world; | ||
48 | m_body1 = obj1; | 48 | m_body1 = obj1; |
49 | m_body2 = obj2; | 49 | m_body2 = obj2; |
50 | m_constraint = new BulletConstraint( | 50 | m_constraint = PhysicsScene.PE.Create6DofConstraint(m_world, m_body1, m_body2, |
51 | BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr, | ||
52 | frame1, frame1rot, | 51 | frame1, frame1rot, |
53 | frame2, frame2rot, | 52 | frame2, frame2rot, |
54 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | 53 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); |
55 | m_enabled = true; | 54 | m_enabled = true; |
56 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | 55 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", |
57 | BSScene.DetailLogZero, world.worldID, | 56 | BSScene.DetailLogZero, world.worldID, |
58 | obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); | 57 | obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); |
59 | } | 58 | } |
60 | 59 | ||
61 | public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2, | 60 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, |
62 | Vector3 joinPoint, | 61 | Vector3 joinPoint, |
63 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | 62 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) |
63 | : base(world) | ||
64 | { | 64 | { |
65 | m_world = world; | ||
66 | m_body1 = obj1; | 65 | m_body1 = obj1; |
67 | m_body2 = obj2; | 66 | m_body2 = obj2; |
68 | if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero) | 67 | if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody) |
69 | { | 68 | { |
70 | world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | 69 | world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", |
71 | BSScene.DetailLogZero, world.worldID, | 70 | BSScene.DetailLogZero, world.worldID, |
72 | obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); | 71 | obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); |
73 | world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | 72 | world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", |
74 | LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); | 73 | LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); |
75 | m_enabled = false; | 74 | m_enabled = false; |
76 | } | 75 | } |
77 | else | 76 | else |
78 | { | 77 | { |
79 | m_constraint = new BulletConstraint( | 78 | m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2, |
80 | BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr, | ||
81 | joinPoint, | 79 | joinPoint, |
82 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | 80 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); |
83 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", | 81 | PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", |
84 | BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"), | 82 | BSScene.DetailLogZero, world.worldID, m_constraint.AddrString, |
85 | obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); | 83 | obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); |
86 | if (m_constraint.ptr == IntPtr.Zero) | 84 | if (!m_constraint.HasPhysicalConstraint) |
87 | { | 85 | { |
88 | world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", | 86 | world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", |
89 | LogHeader, obj1.ID, obj2.ID); | 87 | LogHeader, obj1.ID, obj2.ID); |
@@ -101,7 +99,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
101 | bool ret = false; | 99 | bool ret = false; |
102 | if (m_enabled) | 100 | if (m_enabled) |
103 | { | 101 | { |
104 | BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); | 102 | PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot); |
105 | ret = true; | 103 | ret = true; |
106 | } | 104 | } |
107 | return ret; | 105 | return ret; |
@@ -112,9 +110,9 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
112 | bool ret = false; | 110 | bool ret = false; |
113 | if (m_enabled) | 111 | if (m_enabled) |
114 | { | 112 | { |
115 | BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); | 113 | PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); |
116 | BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); | 114 | PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); |
117 | BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); | 115 | PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); |
118 | ret = true; | 116 | ret = true; |
119 | } | 117 | } |
120 | return ret; | 118 | return ret; |
@@ -125,7 +123,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
125 | bool ret = false; | 123 | bool ret = false; |
126 | float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; | 124 | float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; |
127 | if (m_enabled) | 125 | if (m_enabled) |
128 | ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff); | 126 | ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff); |
129 | return ret; | 127 | return ret; |
130 | } | 128 | } |
131 | 129 | ||
@@ -135,7 +133,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
135 | float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; | 133 | float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; |
136 | if (m_enabled) | 134 | if (m_enabled) |
137 | { | 135 | { |
138 | ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce); | 136 | ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce); |
139 | m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", | 137 | m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", |
140 | BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); | 138 | BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); |
141 | } | 139 | } |
@@ -146,7 +144,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
146 | { | 144 | { |
147 | bool ret = false; | 145 | bool ret = false; |
148 | if (m_enabled) | 146 | if (m_enabled) |
149 | ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold); | 147 | ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold); |
150 | return ret; | 148 | return ret; |
151 | } | 149 | } |
152 | } | 150 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs index a9fd826..2aeff25 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs | |||
@@ -41,9 +41,9 @@ public sealed class BSConstraintCollection : IDisposable | |||
41 | delegate bool ConstraintAction(BSConstraint constrain); | 41 | delegate bool ConstraintAction(BSConstraint constrain); |
42 | 42 | ||
43 | private List<BSConstraint> m_constraints; | 43 | private List<BSConstraint> m_constraints; |
44 | private BulletSim m_world; | 44 | private BulletWorld m_world; |
45 | 45 | ||
46 | public BSConstraintCollection(BulletSim world) | 46 | public BSConstraintCollection(BulletWorld world) |
47 | { | 47 | { |
48 | m_world = world; | 48 | m_world = world; |
49 | m_constraints = new List<BSConstraint>(); | 49 | m_constraints = new List<BSConstraint>(); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs index ed3ffa7..7714a03 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs | |||
@@ -36,19 +36,17 @@ public sealed class BSConstraintHinge : BSConstraint | |||
36 | { | 36 | { |
37 | public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } | 37 | public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } |
38 | 38 | ||
39 | public BSConstraintHinge(BulletSim world, BulletBody obj1, BulletBody obj2, | 39 | public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2, |
40 | Vector3 pivotInA, Vector3 pivotInB, | 40 | Vector3 pivotInA, Vector3 pivotInB, |
41 | Vector3 axisInA, Vector3 axisInB, | 41 | Vector3 axisInA, Vector3 axisInB, |
42 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | 42 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) |
43 | : base(world) | ||
43 | { | 44 | { |
44 | m_world = world; | ||
45 | m_body1 = obj1; | 45 | m_body1 = obj1; |
46 | m_body2 = obj2; | 46 | m_body2 = obj2; |
47 | m_constraint = new BulletConstraint( | 47 | m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2, |
48 | BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr, | 48 | pivotInA, pivotInB, axisInA, axisInB, |
49 | pivotInA, pivotInB, | 49 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); |
50 | axisInA, axisInB, | ||
51 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
52 | m_enabled = true; | 50 | m_enabled = true; |
53 | } | 51 | } |
54 | 52 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index dbc9039..13c2539 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -24,30 +24,17 @@ | |||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 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. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * | 26 | * |
27 | 27 | * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial | |
28 | /* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to | 28 | * are Copyright (c) 2009 Linden Research, Inc and are used under their license |
29 | * call the BulletSim system. | 29 | * of Creative Commons Attribution-Share Alike 3.0 |
30 | */ | 30 | * (http://creativecommons.org/licenses/by-sa/3.0/). |
31 | /* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces | ||
32 | * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: | ||
33 | * ODEPrim.cs contains methods dealing with Prim editing, Prim | ||
34 | * characteristics and Kinetic motion. | ||
35 | * ODEDynamics.cs contains methods dealing with Prim Physical motion | ||
36 | * (dynamics) and the associated settings. Old Linear and angular | ||
37 | * motors for dynamic motion have been replace with MoveLinear() | ||
38 | * and MoveAngular(); 'Physical' is used only to switch ODE dynamic | ||
39 | * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to | ||
40 | * switch between 'VEHICLE' parameter use and general dynamics | ||
41 | * settings use. | ||
42 | */ | 31 | */ |
43 | 32 | ||
44 | using System; | 33 | using System; |
45 | using System.Collections.Generic; | 34 | using System.Collections.Generic; |
46 | using System.Reflection; | 35 | using System.Reflection; |
47 | using System.Runtime.InteropServices; | 36 | using System.Runtime.InteropServices; |
48 | using log4net; | ||
49 | using OpenMetaverse; | 37 | using OpenMetaverse; |
50 | using OpenSim.Framework; | ||
51 | using OpenSim.Region.Physics.Manager; | 38 | using OpenSim.Region.Physics.Manager; |
52 | 39 | ||
53 | namespace OpenSim.Region.Physics.BulletSPlugin | 40 | namespace OpenSim.Region.Physics.BulletSPlugin |
@@ -80,10 +67,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
80 | private Quaternion m_referenceFrame = Quaternion.Identity; | 67 | private Quaternion m_referenceFrame = Quaternion.Identity; |
81 | 68 | ||
82 | // Linear properties | 69 | // Linear properties |
70 | private BSVMotor m_linearMotor = new BSVMotor("LinearMotor"); | ||
83 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | 71 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time |
84 | private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center | 72 | private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center |
85 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL | 73 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL |
86 | private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body | ||
87 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | 74 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; |
88 | private float m_linearMotorDecayTimescale = 0; | 75 | private float m_linearMotorDecayTimescale = 0; |
89 | private float m_linearMotorTimescale = 0; | 76 | private float m_linearMotorTimescale = 0; |
@@ -93,16 +80,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
93 | // private Vector3 m_linearMotorOffset = Vector3.Zero; | 80 | // private Vector3 m_linearMotorOffset = Vector3.Zero; |
94 | 81 | ||
95 | //Angular properties | 82 | //Angular properties |
83 | private BSVMotor m_angularMotor = new BSVMotor("AngularMotor"); | ||
96 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | 84 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor |
97 | // private int m_angularMotorApply = 0; // application frame counter | 85 | // private int m_angularMotorApply = 0; // application frame counter |
98 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity | 86 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity |
99 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | 87 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate |
100 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | 88 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate |
101 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | 89 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate |
102 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body | 90 | private Vector3 m_lastAngularVelocity = Vector3.Zero; |
103 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body | 91 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body |
104 | 92 | ||
105 | //Deflection properties | 93 | //Deflection properties |
94 | private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection"); | ||
106 | private float m_angularDeflectionEfficiency = 0; | 95 | private float m_angularDeflectionEfficiency = 0; |
107 | private float m_angularDeflectionTimescale = 0; | 96 | private float m_angularDeflectionTimescale = 0; |
108 | private float m_linearDeflectionEfficiency = 0; | 97 | private float m_linearDeflectionEfficiency = 0; |
@@ -114,6 +103,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
114 | private float m_bankingTimescale = 0; | 103 | private float m_bankingTimescale = 0; |
115 | 104 | ||
116 | //Hover and Buoyancy properties | 105 | //Hover and Buoyancy properties |
106 | private BSVMotor m_hoverMotor = new BSVMotor("Hover"); | ||
117 | private float m_VhoverHeight = 0f; | 107 | private float m_VhoverHeight = 0f; |
118 | private float m_VhoverEfficiency = 0f; | 108 | private float m_VhoverEfficiency = 0f; |
119 | private float m_VhoverTimescale = 0f; | 109 | private float m_VhoverTimescale = 0f; |
@@ -124,8 +114,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
124 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. | 114 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. |
125 | 115 | ||
126 | //Attractor properties | 116 | //Attractor properties |
127 | private float m_verticalAttractionEfficiency = 1.0f; // damped | 117 | private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); |
128 | private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. | 118 | private float m_verticalAttractionEfficiency = 1.0f; // damped |
119 | private float m_verticalAttractionCutoff = 500f; // per the documentation | ||
120 | // Timescale > cutoff means no vert attractor. | ||
121 | private float m_verticalAttractionTimescale = 510f; | ||
122 | |||
123 | // Just some recomputed constants: | ||
124 | static readonly float PIOverFour = ((float)Math.PI) / 4f; | ||
125 | static readonly float PIOverTwo = ((float)Math.PI) / 2f; | ||
129 | 126 | ||
130 | public BSDynamics(BSScene myScene, BSPrim myPrim) | 127 | public BSDynamics(BSScene myScene, BSPrim myPrim) |
131 | { | 128 | { |
@@ -137,7 +134,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
137 | // Return 'true' if this vehicle is doing vehicle things | 134 | // Return 'true' if this vehicle is doing vehicle things |
138 | public bool IsActive | 135 | public bool IsActive |
139 | { | 136 | { |
140 | get { return Type != Vehicle.TYPE_NONE; } | 137 | get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; } |
141 | } | 138 | } |
142 | 139 | ||
143 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | 140 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) |
@@ -152,13 +149,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
152 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); | 149 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); |
153 | break; | 150 | break; |
154 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | 151 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: |
155 | m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); | 152 | m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); |
153 | m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; | ||
156 | break; | 154 | break; |
157 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | 155 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: |
158 | m_angularMotorTimescale = Math.Max(pValue, 0.01f); | 156 | m_angularMotorTimescale = Math.Max(pValue, 0.01f); |
157 | m_angularMotor.TimeScale = m_angularMotorTimescale; | ||
159 | break; | 158 | break; |
160 | case Vehicle.BANKING_EFFICIENCY: | 159 | case Vehicle.BANKING_EFFICIENCY: |
161 | m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); | 160 | m_bankingEfficiency = ClampInRange(-1f, pValue, 1f); |
162 | break; | 161 | break; |
163 | case Vehicle.BANKING_MIX: | 162 | case Vehicle.BANKING_MIX: |
164 | m_bankingMix = Math.Max(pValue, 0.01f); | 163 | m_bankingMix = Math.Max(pValue, 0.01f); |
@@ -167,10 +166,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
167 | m_bankingTimescale = Math.Max(pValue, 0.01f); | 166 | m_bankingTimescale = Math.Max(pValue, 0.01f); |
168 | break; | 167 | break; |
169 | case Vehicle.BUOYANCY: | 168 | case Vehicle.BUOYANCY: |
170 | m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); | 169 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); |
171 | break; | 170 | break; |
172 | case Vehicle.HOVER_EFFICIENCY: | 171 | case Vehicle.HOVER_EFFICIENCY: |
173 | m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); | 172 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); |
174 | break; | 173 | break; |
175 | case Vehicle.HOVER_HEIGHT: | 174 | case Vehicle.HOVER_HEIGHT: |
176 | m_VhoverHeight = pValue; | 175 | m_VhoverHeight = pValue; |
@@ -185,33 +184,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
185 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); | 184 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); |
186 | break; | 185 | break; |
187 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | 186 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: |
188 | m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); | 187 | m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); |
188 | m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; | ||
189 | break; | 189 | break; |
190 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | 190 | case Vehicle.LINEAR_MOTOR_TIMESCALE: |
191 | m_linearMotorTimescale = Math.Max(pValue, 0.01f); | 191 | m_linearMotorTimescale = Math.Max(pValue, 0.01f); |
192 | m_linearMotor.TimeScale = m_linearMotorTimescale; | ||
192 | break; | 193 | break; |
193 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | 194 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: |
194 | m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); | 195 | m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f); |
196 | m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; | ||
195 | break; | 197 | break; |
196 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | 198 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: |
197 | m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); | 199 | m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); |
200 | m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale; | ||
198 | break; | 201 | break; |
199 | 202 | ||
200 | // These are vector properties but the engine lets you use a single float value to | 203 | // These are vector properties but the engine lets you use a single float value to |
201 | // set all of the components to the same value | 204 | // set all of the components to the same value |
202 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 205 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
203 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | 206 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); |
207 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
204 | break; | 208 | break; |
205 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 209 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
206 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | 210 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); |
207 | // m_angularMotorApply = 100; | 211 | m_angularMotor.SetTarget(m_angularMotorDirection); |
208 | break; | 212 | break; |
209 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 213 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
210 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | 214 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); |
215 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
211 | break; | 216 | break; |
212 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 217 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
213 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | 218 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); |
214 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | 219 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); |
220 | m_linearMotor.SetTarget(m_linearMotorDirection); | ||
215 | break; | 221 | break; |
216 | case Vehicle.LINEAR_MOTOR_OFFSET: | 222 | case Vehicle.LINEAR_MOTOR_OFFSET: |
217 | m_linearMotorOffset = new Vector3(pValue, pValue, pValue); | 223 | m_linearMotorOffset = new Vector3(pValue, pValue, pValue); |
@@ -227,21 +233,24 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
227 | { | 233 | { |
228 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 234 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
229 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 235 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
236 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
230 | break; | 237 | break; |
231 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 238 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
232 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | 239 | // Limit requested angular speed to 2 rps= 4 pi rads/sec |
233 | pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); | 240 | pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f); |
234 | pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); | 241 | pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); |
235 | pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); | 242 | pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); |
236 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 243 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
237 | // m_angularMotorApply = 100; | 244 | m_angularMotor.SetTarget(m_angularMotorDirection); |
238 | break; | 245 | break; |
239 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 246 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
240 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 247 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
248 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
241 | break; | 249 | break; |
242 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 250 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
243 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 251 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
244 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | 252 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); |
253 | m_linearMotor.SetTarget(m_linearMotorDirection); | ||
245 | break; | 254 | break; |
246 | case Vehicle.LINEAR_MOTOR_OFFSET: | 255 | case Vehicle.LINEAR_MOTOR_OFFSET: |
247 | m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | 256 | m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -303,7 +312,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
303 | m_VhoverEfficiency = 0; | 312 | m_VhoverEfficiency = 0; |
304 | m_VhoverTimescale = 0; | 313 | m_VhoverTimescale = 0; |
305 | m_VehicleBuoyancy = 0; | 314 | m_VehicleBuoyancy = 0; |
306 | 315 | ||
307 | m_linearDeflectionEfficiency = 1; | 316 | m_linearDeflectionEfficiency = 1; |
308 | m_linearDeflectionTimescale = 1; | 317 | m_linearDeflectionTimescale = 1; |
309 | 318 | ||
@@ -319,6 +328,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
319 | 328 | ||
320 | m_referenceFrame = Quaternion.Identity; | 329 | m_referenceFrame = Quaternion.Identity; |
321 | m_flags = (VehicleFlag)0; | 330 | m_flags = (VehicleFlag)0; |
331 | |||
322 | break; | 332 | break; |
323 | 333 | ||
324 | case Vehicle.TYPE_SLED: | 334 | case Vehicle.TYPE_SLED: |
@@ -351,10 +361,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
351 | m_bankingMix = 1; | 361 | m_bankingMix = 1; |
352 | 362 | ||
353 | m_referenceFrame = Quaternion.Identity; | 363 | m_referenceFrame = Quaternion.Identity; |
354 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | 364 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
355 | m_flags &= | 365 | | VehicleFlag.HOVER_TERRAIN_ONLY |
356 | ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | 366 | | VehicleFlag.HOVER_GLOBAL_HEIGHT |
357 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | 367 | | VehicleFlag.HOVER_UP_ONLY); |
368 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | ||
369 | | VehicleFlag.LIMIT_ROLL_ONLY | ||
370 | | VehicleFlag.LIMIT_MOTOR_UP); | ||
371 | |||
358 | break; | 372 | break; |
359 | case Vehicle.TYPE_CAR: | 373 | case Vehicle.TYPE_CAR: |
360 | m_linearMotorDirection = Vector3.Zero; | 374 | m_linearMotorDirection = Vector3.Zero; |
@@ -498,6 +512,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
498 | m_bankingEfficiency = 0; | 512 | m_bankingEfficiency = 0; |
499 | m_bankingMix = 0.7f; | 513 | m_bankingMix = 0.7f; |
500 | m_bankingTimescale = 5; | 514 | m_bankingTimescale = 5; |
515 | |||
501 | m_referenceFrame = Quaternion.Identity; | 516 | m_referenceFrame = Quaternion.Identity; |
502 | 517 | ||
503 | m_referenceFrame = Quaternion.Identity; | 518 | m_referenceFrame = Quaternion.Identity; |
@@ -510,6 +525,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
510 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); | 525 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); |
511 | break; | 526 | break; |
512 | } | 527 | } |
528 | |||
529 | // Update any physical parameters based on this type. | ||
530 | Refresh(); | ||
531 | |||
532 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, | ||
533 | m_linearMotorDecayTimescale, m_linearFrictionTimescale, | ||
534 | 1f); | ||
535 | m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
536 | |||
537 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, | ||
538 | m_angularMotorDecayTimescale, m_angularFrictionTimescale, | ||
539 | 1f); | ||
540 | m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
541 | |||
542 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, | ||
543 | BSMotor.Infinite, BSMotor.InfiniteVector, | ||
544 | m_verticalAttractionEfficiency); | ||
545 | // Z goes away and we keep X and Y | ||
546 | m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f); | ||
547 | m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
513 | } | 548 | } |
514 | 549 | ||
515 | // Some of the properties of this prim may have changed. | 550 | // Some of the properties of this prim may have changed. |
@@ -518,13 +553,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
518 | { | 553 | { |
519 | if (IsActive) | 554 | if (IsActive) |
520 | { | 555 | { |
521 | // Friction effects are handled by this vehicle code | 556 | // Remember the mass so we don't have to fetch it every step |
522 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); | 557 | m_vehicleMass = Prim.Linkset.LinksetMass; |
523 | BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f); | ||
524 | 558 | ||
525 | // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f); | 559 | // Friction affects are handled by this vehicle code |
560 | float friction = 0f; | ||
561 | PhysicsScene.PE.SetFriction(Prim.PhysBody, friction); | ||
526 | 562 | ||
527 | VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID); | 563 | // Moderate angular movement introduced by Bullet. |
564 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. | ||
565 | // Maybe compute linear and angular factor and damping from params. | ||
566 | float angularDamping = BSParam.VehicleAngularDamping; | ||
567 | PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, angularDamping); | ||
568 | |||
569 | // Vehicles report collision events so we know when it's on the ground | ||
570 | PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
571 | |||
572 | Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass); | ||
573 | PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, localInertia); | ||
574 | PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody); | ||
575 | |||
576 | Vector3 grav = PhysicsScene.DefaultGravity * (1f - Prim.Buoyancy); | ||
577 | PhysicsScene.PE.SetGravity(Prim.PhysBody, grav); | ||
578 | |||
579 | VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}", | ||
580 | Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping); | ||
581 | } | ||
582 | else | ||
583 | { | ||
584 | PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
528 | } | 585 | } |
529 | } | 586 | } |
530 | 587 | ||
@@ -546,116 +603,342 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
546 | Refresh(); | 603 | Refresh(); |
547 | } | 604 | } |
548 | 605 | ||
606 | #region Known vehicle value functions | ||
607 | // Vehicle physical parameters that we buffer from constant getting and setting. | ||
608 | // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set. | ||
609 | // Changing is remembered and the parameter is stored back into the physics engine only if updated. | ||
610 | // This does two things: 1) saves continuious calls into unmanaged code, and | ||
611 | // 2) signals when a physics property update must happen back to the simulator | ||
612 | // to update values modified for the vehicle. | ||
613 | private int m_knownChanged; | ||
614 | private int m_knownHas; | ||
615 | private float m_knownTerrainHeight; | ||
616 | private float m_knownWaterLevel; | ||
617 | private Vector3 m_knownPosition; | ||
618 | private Vector3 m_knownVelocity; | ||
619 | private Vector3 m_knownForce; | ||
620 | private Quaternion m_knownOrientation; | ||
621 | private Vector3 m_knownRotationalVelocity; | ||
622 | private Vector3 m_knownRotationalForce; | ||
623 | private Vector3 m_knownForwardVelocity; // vehicle relative forward speed | ||
624 | |||
625 | private const int m_knownChangedPosition = 1 << 0; | ||
626 | private const int m_knownChangedVelocity = 1 << 1; | ||
627 | private const int m_knownChangedForce = 1 << 2; | ||
628 | private const int m_knownChangedOrientation = 1 << 3; | ||
629 | private const int m_knownChangedRotationalVelocity = 1 << 4; | ||
630 | private const int m_knownChangedRotationalForce = 1 << 5; | ||
631 | private const int m_knownChangedTerrainHeight = 1 << 6; | ||
632 | private const int m_knownChangedWaterLevel = 1 << 7; | ||
633 | private const int m_knownChangedForwardVelocity = 1 << 8; | ||
634 | |||
635 | private void ForgetKnownVehicleProperties() | ||
636 | { | ||
637 | m_knownHas = 0; | ||
638 | m_knownChanged = 0; | ||
639 | } | ||
640 | // Push all the changed values back into the physics engine | ||
641 | private void PushKnownChanged() | ||
642 | { | ||
643 | if (m_knownChanged != 0) | ||
644 | { | ||
645 | if ((m_knownChanged & m_knownChangedPosition) != 0) | ||
646 | Prim.ForcePosition = m_knownPosition; | ||
647 | |||
648 | if ((m_knownChanged & m_knownChangedOrientation) != 0) | ||
649 | Prim.ForceOrientation = m_knownOrientation; | ||
650 | |||
651 | if ((m_knownChanged & m_knownChangedVelocity) != 0) | ||
652 | { | ||
653 | Prim.ForceVelocity = m_knownVelocity; | ||
654 | PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, VehicleVelocity); | ||
655 | } | ||
656 | |||
657 | if ((m_knownChanged & m_knownChangedForce) != 0) | ||
658 | Prim.AddForce((Vector3)m_knownForce, false, true); | ||
659 | |||
660 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) | ||
661 | { | ||
662 | Prim.ForceRotationalVelocity = m_knownRotationalVelocity; | ||
663 | // Fake out Bullet by making it think the velocity is the same as last time. | ||
664 | PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); | ||
665 | } | ||
666 | |||
667 | if ((m_knownChanged & m_knownChangedRotationalForce) != 0) | ||
668 | Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true); | ||
669 | |||
670 | // If we set one of the values (ie, the physics engine didn't do it) we must force | ||
671 | // an UpdateProperties event to send the changes up to the simulator. | ||
672 | PhysicsScene.PE.PushUpdate(Prim.PhysBody); | ||
673 | } | ||
674 | m_knownChanged = 0; | ||
675 | } | ||
676 | |||
677 | // Since the computation of terrain height can be a little involved, this routine | ||
678 | // is used to fetch the height only once for each vehicle simulation step. | ||
679 | private float GetTerrainHeight(Vector3 pos) | ||
680 | { | ||
681 | if ((m_knownHas & m_knownChangedTerrainHeight) == 0) | ||
682 | { | ||
683 | m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | ||
684 | m_knownHas |= m_knownChangedTerrainHeight; | ||
685 | } | ||
686 | return m_knownTerrainHeight; | ||
687 | } | ||
688 | |||
689 | // Since the computation of water level can be a little involved, this routine | ||
690 | // is used ot fetch the level only once for each vehicle simulation step. | ||
691 | private float GetWaterLevel(Vector3 pos) | ||
692 | { | ||
693 | if ((m_knownHas & m_knownChangedWaterLevel) == 0) | ||
694 | { | ||
695 | m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); | ||
696 | m_knownHas |= m_knownChangedWaterLevel; | ||
697 | } | ||
698 | return (float)m_knownWaterLevel; | ||
699 | } | ||
700 | |||
701 | private Vector3 VehiclePosition | ||
702 | { | ||
703 | get | ||
704 | { | ||
705 | if ((m_knownHas & m_knownChangedPosition) == 0) | ||
706 | { | ||
707 | m_knownPosition = Prim.ForcePosition; | ||
708 | m_knownHas |= m_knownChangedPosition; | ||
709 | } | ||
710 | return m_knownPosition; | ||
711 | } | ||
712 | set | ||
713 | { | ||
714 | m_knownPosition = value; | ||
715 | m_knownChanged |= m_knownChangedPosition; | ||
716 | m_knownHas |= m_knownChangedPosition; | ||
717 | } | ||
718 | } | ||
719 | |||
720 | private Quaternion VehicleOrientation | ||
721 | { | ||
722 | get | ||
723 | { | ||
724 | if ((m_knownHas & m_knownChangedOrientation) == 0) | ||
725 | { | ||
726 | m_knownOrientation = Prim.ForceOrientation; | ||
727 | m_knownHas |= m_knownChangedOrientation; | ||
728 | } | ||
729 | return m_knownOrientation; | ||
730 | } | ||
731 | set | ||
732 | { | ||
733 | m_knownOrientation = value; | ||
734 | m_knownChanged |= m_knownChangedOrientation; | ||
735 | m_knownHas |= m_knownChangedOrientation; | ||
736 | } | ||
737 | } | ||
738 | |||
739 | private Vector3 VehicleVelocity | ||
740 | { | ||
741 | get | ||
742 | { | ||
743 | if ((m_knownHas & m_knownChangedVelocity) == 0) | ||
744 | { | ||
745 | m_knownVelocity = Prim.ForceVelocity; | ||
746 | m_knownHas |= m_knownChangedVelocity; | ||
747 | } | ||
748 | return (Vector3)m_knownVelocity; | ||
749 | } | ||
750 | set | ||
751 | { | ||
752 | m_knownVelocity = value; | ||
753 | m_knownChanged |= m_knownChangedVelocity; | ||
754 | m_knownHas |= m_knownChangedVelocity; | ||
755 | } | ||
756 | } | ||
757 | |||
758 | private void VehicleAddForce(Vector3 aForce) | ||
759 | { | ||
760 | if ((m_knownHas & m_knownChangedForce) == 0) | ||
761 | { | ||
762 | m_knownForce = Vector3.Zero; | ||
763 | } | ||
764 | m_knownForce += aForce; | ||
765 | m_knownChanged |= m_knownChangedForce; | ||
766 | m_knownHas |= m_knownChangedForce; | ||
767 | } | ||
768 | |||
769 | private Vector3 VehicleRotationalVelocity | ||
770 | { | ||
771 | get | ||
772 | { | ||
773 | if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) | ||
774 | { | ||
775 | m_knownRotationalVelocity = Prim.ForceRotationalVelocity; | ||
776 | m_knownHas |= m_knownChangedRotationalVelocity; | ||
777 | } | ||
778 | return (Vector3)m_knownRotationalVelocity; | ||
779 | } | ||
780 | set | ||
781 | { | ||
782 | m_knownRotationalVelocity = value; | ||
783 | m_knownChanged |= m_knownChangedRotationalVelocity; | ||
784 | m_knownHas |= m_knownChangedRotationalVelocity; | ||
785 | } | ||
786 | } | ||
787 | private void VehicleAddAngularForce(Vector3 aForce) | ||
788 | { | ||
789 | if ((m_knownHas & m_knownChangedRotationalForce) == 0) | ||
790 | { | ||
791 | m_knownRotationalForce = Vector3.Zero; | ||
792 | } | ||
793 | m_knownRotationalForce += aForce; | ||
794 | m_knownChanged |= m_knownChangedRotationalForce; | ||
795 | m_knownHas |= m_knownChangedRotationalForce; | ||
796 | } | ||
797 | // Vehicle relative forward velocity | ||
798 | private Vector3 VehicleForwardVelocity | ||
799 | { | ||
800 | get | ||
801 | { | ||
802 | if ((m_knownHas & m_knownChangedForwardVelocity) == 0) | ||
803 | { | ||
804 | m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); | ||
805 | m_knownHas |= m_knownChangedForwardVelocity; | ||
806 | } | ||
807 | return m_knownForwardVelocity; | ||
808 | } | ||
809 | } | ||
810 | private float VehicleForwardSpeed | ||
811 | { | ||
812 | get | ||
813 | { | ||
814 | return VehicleForwardVelocity.X; | ||
815 | } | ||
816 | } | ||
817 | |||
818 | #endregion // Known vehicle value functions | ||
819 | |||
549 | // One step of the vehicle properties for the next 'pTimestep' seconds. | 820 | // One step of the vehicle properties for the next 'pTimestep' seconds. |
550 | internal void Step(float pTimestep) | 821 | internal void Step(float pTimestep) |
551 | { | 822 | { |
552 | if (!IsActive) return; | 823 | if (!IsActive) return; |
553 | 824 | ||
554 | // DEBUG | 825 | if (PhysicsScene.VehiclePhysicalLoggingEnabled) |
555 | // Because Bullet does apply forces to the vehicle, our last computed | 826 | PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); |
556 | // linear and angular velocities are not what is happening now. | ||
557 | // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity; | ||
558 | // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep; | ||
559 | // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time | ||
560 | // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG: | ||
561 | // END DEBUG | ||
562 | 827 | ||
563 | m_vehicleMass = Prim.Linkset.LinksetMass; | 828 | ForgetKnownVehicleProperties(); |
564 | 829 | ||
565 | MoveLinear(pTimestep); | 830 | MoveLinear(pTimestep); |
566 | // Commented out for debug | ||
567 | MoveAngular(pTimestep); | 831 | MoveAngular(pTimestep); |
568 | // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG | ||
569 | // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG | ||
570 | 832 | ||
571 | LimitRotation(pTimestep); | 833 | LimitRotation(pTimestep); |
572 | 834 | ||
573 | // remember the position so next step we can limit absolute movement effects | 835 | // remember the position so next step we can limit absolute movement effects |
574 | m_lastPositionVector = Prim.ForcePosition; | 836 | m_lastPositionVector = VehiclePosition; |
575 | 837 | ||
576 | VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG | 838 | // If we forced the changing of some vehicle parameters, update the values and |
577 | Prim.LocalID, | 839 | // for the physics engine to note the changes so an UpdateProperties event will happen. |
578 | BulletSimAPI.GetFriction2(Prim.PhysBody.ptr), | 840 | PushKnownChanged(); |
579 | BulletSimAPI.GetGravity2(Prim.PhysBody.ptr), | 841 | |
580 | Prim.Inertia, | 842 | if (PhysicsScene.VehiclePhysicalLoggingEnabled) |
581 | m_vehicleMass | 843 | PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); |
582 | ); | 844 | |
583 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", | 845 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", |
584 | Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); | 846 | Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity); |
585 | }// end Step | 847 | } |
586 | 848 | ||
587 | // Apply the effect of the linear motor. | 849 | // Apply the effect of the linear motor and other linear motions (like hover and float). |
588 | // Also does hover and float. | ||
589 | private void MoveLinear(float pTimestep) | 850 | private void MoveLinear(float pTimestep) |
590 | { | 851 | { |
591 | // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates | 852 | Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); |
592 | // m_lastLinearVelocityVector is the current speed we are moving in that direction | ||
593 | if (m_linearMotorDirection.LengthSquared() > 0.001f) | ||
594 | { | ||
595 | Vector3 origDir = m_linearMotorDirection; // DEBUG | ||
596 | Vector3 origVel = m_lastLinearVelocityVector; // DEBUG | ||
597 | // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison | ||
598 | Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG | ||
599 | 853 | ||
600 | // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete | 854 | // The movement computed in the linear motor is relative to the vehicle |
601 | Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep; | 855 | // coordinates. Rotate the movement to world coordinates. |
602 | m_lastLinearVelocityVector += addAmount; | 856 | linearMotorContribution *= VehicleOrientation; |
603 | 857 | ||
604 | float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; | 858 | // ================================================================== |
605 | m_linearMotorDirection *= (1f - decayFactor); | 859 | // Buoyancy: force to overcome gravity. |
860 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | ||
861 | // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity. | ||
862 | Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy; | ||
606 | 863 | ||
607 | // Rotate new object velocity from vehicle relative to world coordinates | 864 | Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep); |
608 | m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation; | ||
609 | 865 | ||
610 | // Apply friction for next time | 866 | Vector3 hoverContribution = ComputeLinearHover(pTimestep); |
611 | Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep; | ||
612 | m_lastLinearVelocityVector *= (Vector3.One - frictionFactor); | ||
613 | 867 | ||
614 | VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}", | 868 | ComputeLinearBlockingEndPoint(pTimestep); |
615 | Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, | 869 | |
616 | m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); | 870 | Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep); |
617 | } | 871 | |
618 | else | 872 | // ================================================================== |
619 | { | 873 | Vector3 newVelocity = linearMotorContribution |
620 | // if what remains of direction is very small, zero it. | 874 | + terrainHeightContribution |
621 | m_linearMotorDirection = Vector3.Zero; | 875 | + hoverContribution |
622 | m_lastLinearVelocityVector = Vector3.Zero; | 876 | + limitMotorUpContribution; |
623 | m_newVelocity = Vector3.Zero; | 877 | |
878 | Vector3 newForce = buoyancyContribution; | ||
879 | |||
880 | // If not changing some axis, reduce out velocity | ||
881 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | ||
882 | newVelocity.X = 0; | ||
883 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | ||
884 | newVelocity.Y = 0; | ||
885 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
886 | newVelocity.Z = 0; | ||
624 | 887 | ||
625 | VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); | 888 | // ================================================================== |
889 | // Clamp high or low velocities | ||
890 | float newVelocityLengthSq = newVelocity.LengthSquared(); | ||
891 | if (newVelocityLengthSq > 1000f) | ||
892 | { | ||
893 | newVelocity /= newVelocity.Length(); | ||
894 | newVelocity *= 1000f; | ||
626 | } | 895 | } |
896 | else if (newVelocityLengthSq < 0.001f) | ||
897 | newVelocity = Vector3.Zero; | ||
627 | 898 | ||
628 | // m_newVelocity is velocity computed from linear motor in world coordinates | 899 | // ================================================================== |
900 | // Stuff new linear velocity into the vehicle. | ||
901 | // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us. | ||
902 | VehicleVelocity = newVelocity; | ||
629 | 903 | ||
630 | // Gravity and Buoyancy | 904 | // Other linear forces are applied as forces. |
631 | // There is some gravity, make a gravity force vector that is applied after object velocity. | 905 | Vector3 totalDownForce = newForce * m_vehicleMass; |
632 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | 906 | if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f)) |
633 | Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); | 907 | { |
908 | VehicleAddForce(totalDownForce); | ||
909 | } | ||
634 | 910 | ||
635 | /* | 911 | VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}", |
636 | * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ... | 912 | Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding); |
637 | // Preserve the current Z velocity | 913 | VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}", |
638 | Vector3 vel_now = m_prim.Velocity; | 914 | Prim.LocalID, |
639 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity | 915 | linearMotorContribution, terrainHeightContribution, hoverContribution, |
640 | */ | 916 | limitMotorUpContribution, buoyancyContribution |
917 | ); | ||
641 | 918 | ||
642 | Vector3 pos = Prim.ForcePosition; | 919 | } // end MoveLinear() |
643 | // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); | ||
644 | 920 | ||
921 | public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep) | ||
922 | { | ||
923 | Vector3 ret = Vector3.Zero; | ||
645 | // If below the terrain, move us above the ground a little. | 924 | // If below the terrain, move us above the ground a little. |
646 | float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | 925 | // TODO: Consider taking the rotated size of the object or possibly casting a ray. |
647 | // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. | 926 | if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) |
648 | // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. | ||
649 | // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; | ||
650 | // if (rotatedSize.Z < terrainHeight) | ||
651 | if (pos.Z < terrainHeight) | ||
652 | { | 927 | { |
653 | pos.Z = terrainHeight + 2; | 928 | // TODO: correct position by applying force rather than forcing position. |
654 | Prim.ForcePosition = pos; | 929 | Vector3 newPosition = VehiclePosition; |
655 | VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); | 930 | newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; |
931 | VehiclePosition = newPosition; | ||
932 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", | ||
933 | Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); | ||
656 | } | 934 | } |
935 | return ret; | ||
936 | } | ||
937 | |||
938 | public Vector3 ComputeLinearHover(float pTimestep) | ||
939 | { | ||
940 | Vector3 ret = Vector3.Zero; | ||
657 | 941 | ||
658 | // Check if hovering | ||
659 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped | 942 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped |
660 | // m_VhoverTimescale: time to achieve height | 943 | // m_VhoverTimescale: time to achieve height |
661 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | 944 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) |
@@ -663,11 +946,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
663 | // We should hover, get the target height | 946 | // We should hover, get the target height |
664 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) | 947 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) |
665 | { | 948 | { |
666 | m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; | 949 | m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight; |
667 | } | 950 | } |
668 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) | 951 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) |
669 | { | 952 | { |
670 | m_VhoverTargetHeight = terrainHeight + m_VhoverHeight; | 953 | m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight; |
671 | } | 954 | } |
672 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) | 955 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) |
673 | { | 956 | { |
@@ -677,45 +960,47 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
677 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) | 960 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) |
678 | { | 961 | { |
679 | // If body is already heigher, use its height as target height | 962 | // If body is already heigher, use its height as target height |
680 | if (pos.Z > m_VhoverTargetHeight) | 963 | if (VehiclePosition.Z > m_VhoverTargetHeight) |
681 | m_VhoverTargetHeight = pos.Z; | 964 | m_VhoverTargetHeight = VehiclePosition.Z; |
682 | } | 965 | } |
966 | |||
683 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | 967 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) |
684 | { | 968 | { |
685 | if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) | 969 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) |
686 | { | 970 | { |
971 | Vector3 pos = VehiclePosition; | ||
687 | pos.Z = m_VhoverTargetHeight; | 972 | pos.Z = m_VhoverTargetHeight; |
688 | Prim.ForcePosition = pos; | 973 | VehiclePosition = pos; |
689 | } | 974 | } |
690 | } | 975 | } |
691 | else | 976 | else |
692 | { | 977 | { |
693 | float verticalError = pos.Z - m_VhoverTargetHeight; | 978 | // Error is positive if below the target and negative if above. |
694 | // RA: where does the 50 come from? | 979 | float verticalError = m_VhoverTargetHeight - VehiclePosition.Z; |
695 | float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); | 980 | float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; |
696 | // Replace Vertical speed with correction figure if significant | 981 | |
697 | if (Math.Abs(verticalError) > 0.01f) | 982 | // TODO: implement m_VhoverEfficiency correctly |
698 | { | 983 | if (Math.Abs(verticalError) > m_VhoverEfficiency) |
699 | m_newVelocity.Z += verticalCorrectionVelocity; | ||
700 | //KF: m_VhoverEfficiency is not yet implemented | ||
701 | } | ||
702 | else if (verticalError < -0.01) | ||
703 | { | ||
704 | m_newVelocity.Z -= verticalCorrectionVelocity; | ||
705 | } | ||
706 | else | ||
707 | { | 984 | { |
708 | m_newVelocity.Z = 0f; | 985 | ret = new Vector3(0f, 0f, verticalCorrectionVelocity); |
709 | } | 986 | } |
710 | } | 987 | } |
711 | 988 | ||
712 | VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); | 989 | VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}", |
990 | Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight); | ||
713 | } | 991 | } |
714 | 992 | ||
993 | return ret; | ||
994 | } | ||
995 | |||
996 | public bool ComputeLinearBlockingEndPoint(float pTimestep) | ||
997 | { | ||
998 | bool changed = false; | ||
999 | |||
1000 | Vector3 pos = VehiclePosition; | ||
715 | Vector3 posChange = pos - m_lastPositionVector; | 1001 | Vector3 posChange = pos - m_lastPositionVector; |
716 | if (m_BlockingEndPoint != Vector3.Zero) | 1002 | if (m_BlockingEndPoint != Vector3.Zero) |
717 | { | 1003 | { |
718 | bool changed = false; | ||
719 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) | 1004 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) |
720 | { | 1005 | { |
721 | pos.X -= posChange.X + 1; | 1006 | pos.X -= posChange.X + 1; |
@@ -743,233 +1028,109 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
743 | } | 1028 | } |
744 | if (changed) | 1029 | if (changed) |
745 | { | 1030 | { |
746 | Prim.ForcePosition = pos; | 1031 | VehiclePosition = pos; |
747 | VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | 1032 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", |
748 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); | 1033 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); |
749 | } | 1034 | } |
750 | } | 1035 | } |
1036 | return changed; | ||
1037 | } | ||
751 | 1038 | ||
752 | #region downForce | 1039 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : |
753 | Vector3 downForce = Vector3.Zero; | 1040 | // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when |
1041 | // used with conjunction with banking: the strength of the banking will decay when the | ||
1042 | // vehicle no longer experiences collisions. The decay timescale is the same as | ||
1043 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering | ||
1044 | // when they are in mid jump. | ||
1045 | // TODO: this code is wrong. Also, what should it do for boats (height from water)? | ||
1046 | // This is just using the ground and a general collision check. Should really be using | ||
1047 | // a downward raycast to find what is below. | ||
1048 | public Vector3 ComputeLinearMotorUp(float pTimestep) | ||
1049 | { | ||
1050 | Vector3 ret = Vector3.Zero; | ||
1051 | float distanceAboveGround = 0f; | ||
754 | 1052 | ||
755 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) | 1053 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) |
756 | { | 1054 | { |
757 | // If the vehicle is motoring into the sky, get it going back down. | 1055 | float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); |
758 | // Is this an angular force or both linear and angular?? | 1056 | distanceAboveGround = VehiclePosition.Z - targetHeight; |
759 | float distanceAboveGround = pos.Z - terrainHeight; | 1057 | // Not colliding if the vehicle is off the ground |
760 | if (distanceAboveGround > 2f) | 1058 | if (!Prim.IsColliding) |
761 | { | 1059 | { |
762 | // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); | ||
763 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); | 1060 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); |
764 | downForce = new Vector3(0, 0, -distanceAboveGround); | 1061 | ret = new Vector3(0, 0, -distanceAboveGround); |
765 | } | 1062 | } |
766 | // TODO: this calculation is all wrong. From the description at | 1063 | // TODO: this calculation is wrong. From the description at |
767 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce | 1064 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce |
768 | // has a decay factor. This says this force should | 1065 | // has a decay factor. This says this force should |
769 | // be computed with a motor. | 1066 | // be computed with a motor. |
770 | VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", | 1067 | // TODO: add interaction with banking. |
771 | Prim.LocalID, distanceAboveGround, downForce); | ||
772 | } | ||
773 | #endregion // downForce | ||
774 | |||
775 | // If not changing some axis, reduce out velocity | ||
776 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | ||
777 | m_newVelocity.X = 0; | ||
778 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | ||
779 | m_newVelocity.Y = 0; | ||
780 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
781 | m_newVelocity.Z = 0; | ||
782 | |||
783 | // Clamp REALLY high or low velocities | ||
784 | if (m_newVelocity.LengthSquared() > 1e6f) | ||
785 | { | ||
786 | m_newVelocity /= m_newVelocity.Length(); | ||
787 | m_newVelocity *= 1000f; | ||
788 | } | ||
789 | else if (m_newVelocity.LengthSquared() < 1e-6f) | ||
790 | m_newVelocity = Vector3.Zero; | ||
791 | |||
792 | // Stuff new linear velocity into the vehicle | ||
793 | Prim.ForceVelocity = m_newVelocity; | ||
794 | // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG | ||
795 | |||
796 | Vector3 totalDownForce = downForce + grav; | ||
797 | if (totalDownForce != Vector3.Zero) | ||
798 | { | ||
799 | Prim.AddForce(totalDownForce * m_vehicleMass, false); | ||
800 | // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false); | ||
801 | } | 1068 | } |
802 | 1069 | VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", | |
803 | VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", | 1070 | Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); |
804 | Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce); | 1071 | return ret; |
805 | 1072 | } | |
806 | } // end MoveLinear() | ||
807 | 1073 | ||
808 | // ======================================================================= | 1074 | // ======================================================================= |
1075 | // ======================================================================= | ||
809 | // Apply the effect of the angular motor. | 1076 | // Apply the effect of the angular motor. |
1077 | // The 'contribution' is how much angular correction velocity each function wants. | ||
1078 | // All the contributions are added together and the resulting velocity is | ||
1079 | // set directly on the vehicle. | ||
810 | private void MoveAngular(float pTimestep) | 1080 | private void MoveAngular(float pTimestep) |
811 | { | 1081 | { |
812 | // m_angularMotorDirection // angular velocity requested by LSL motor | 1082 | // The user wants this many radians per second angular change? |
813 | // m_angularMotorApply // application frame counter | 1083 | Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); |
814 | // m_angularMotorVelocity // current angular motor velocity (ramps up and down) | 1084 | |
815 | // m_angularMotorTimescale // motor angular velocity ramp up rate | 1085 | // ================================================================== |
816 | // m_angularMotorDecayTimescale // motor angular velocity decay rate | 1086 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : |
817 | // m_angularFrictionTimescale // body angular velocity decay rate | 1087 | // This flag prevents linear deflection parallel to world z-axis. This is useful |
818 | // m_lastAngularVelocity // what was last applied to body | 1088 | // for preventing ground vehicles with large linear deflection, like bumper cars, |
819 | 1089 | // from climbing their linear deflection into the sky. | |
820 | if (m_angularMotorDirection.LengthSquared() > 0.0001) | 1090 | // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement |
821 | { | 1091 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) |
822 | Vector3 origVel = m_angularMotorVelocity; | ||
823 | Vector3 origDir = m_angularMotorDirection; | ||
824 | |||
825 | // new velocity += error / ( time to get there / step interval) | ||
826 | // requested direction - current vehicle direction | ||
827 | m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep); | ||
828 | // decay requested direction | ||
829 | m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale)); | ||
830 | |||
831 | VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}", | ||
832 | Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity); | ||
833 | } | ||
834 | else | ||
835 | { | 1092 | { |
836 | m_angularMotorVelocity = Vector3.Zero; | 1093 | angularMotorContribution.X = 0f; |
1094 | angularMotorContribution.Y = 0f; | ||
1095 | VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution); | ||
837 | } | 1096 | } |
838 | 1097 | ||
839 | #region Vertical attactor | 1098 | Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(); |
840 | |||
841 | Vector3 vertattr = Vector3.Zero; | ||
842 | Vector3 deflection = Vector3.Zero; | ||
843 | Vector3 banking = Vector3.Zero; | ||
844 | |||
845 | // If vertical attaction timescale is reasonable and we applied an angular force last time... | ||
846 | if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) | ||
847 | { | ||
848 | float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; | ||
849 | if (Prim.IsColliding) | ||
850 | VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale); | ||
851 | |||
852 | VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | ||
853 | |||
854 | // Create a vector of the vehicle "up" in world coordinates | ||
855 | Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation; | ||
856 | // verticalError.X and .Y are the World error amounts. They are 0 when there is no | ||
857 | // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its | ||
858 | // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall | ||
859 | // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be | ||
860 | // modulated to prevent a stable inverted body. | ||
861 | |||
862 | // Error is 0 (no error) to +/- 2 (max error) | ||
863 | if (verticalError.Z < 0.0f) | ||
864 | { | ||
865 | verticalError.X = 2.0f - verticalError.X; | ||
866 | verticalError.Y = 2.0f - verticalError.Y; | ||
867 | } | ||
868 | // scale it by VAservo (timestep and timescale) | ||
869 | verticalError = verticalError * VAservo; | ||
870 | |||
871 | // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y | ||
872 | // then .X increases, so change Body angular velocity X based on Y, and Y based on X. | ||
873 | // Z is not changed. | ||
874 | vertattr.X = verticalError.Y; | ||
875 | vertattr.Y = - verticalError.X; | ||
876 | vertattr.Z = 0f; | ||
877 | 1099 | ||
878 | // scaling appears better usingsquare-law | 1100 | Vector3 deflectionContribution = ComputeAngularDeflection(); |
879 | Vector3 angularVelocity = Prim.ForceRotationalVelocity; | ||
880 | float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | ||
881 | vertattr.X += bounce * angularVelocity.X; | ||
882 | vertattr.Y += bounce * angularVelocity.Y; | ||
883 | 1101 | ||
884 | VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}", | 1102 | Vector3 bankingContribution = ComputeAngularBanking(); |
885 | Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr); | ||
886 | 1103 | ||
887 | } | 1104 | // ================================================================== |
888 | #endregion // Vertical attactor | 1105 | m_lastVertAttractor = verticalAttractionContribution; |
889 | 1106 | ||
890 | #region Deflection | 1107 | m_lastAngularVelocity = angularMotorContribution |
1108 | + verticalAttractionContribution | ||
1109 | + deflectionContribution | ||
1110 | + bankingContribution; | ||
891 | 1111 | ||
892 | if (m_angularDeflectionEfficiency != 0) | 1112 | // ================================================================== |
1113 | // Apply the correction velocity. | ||
1114 | // TODO: Should this be applied as an angular force (torque)? | ||
1115 | if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | ||
893 | { | 1116 | { |
894 | // Compute a scaled vector that points in the preferred axis (X direction) | 1117 | VehicleRotationalVelocity = m_lastAngularVelocity; |
895 | Vector3 scaledDefaultDirection = | ||
896 | new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0); | ||
897 | // Adding the current vehicle orientation and reference frame displaces the orientation to the frame. | ||
898 | // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point. | ||
899 | Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); | ||
900 | |||
901 | // Scale by efficiency and timescale | ||
902 | deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; | ||
903 | |||
904 | VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", | ||
905 | Prim.LocalID, preferredAxisOfMotion, deflection); | ||
906 | // This deflection computation is not correct. | ||
907 | deflection = Vector3.Zero; | ||
908 | } | ||
909 | |||
910 | #endregion | ||
911 | 1118 | ||
912 | #region Banking | 1119 | VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}", |
913 | 1120 | Prim.LocalID, | |
914 | if (m_bankingEfficiency != 0) | 1121 | angularMotorContribution, verticalAttractionContribution, |
1122 | bankingContribution, deflectionContribution, | ||
1123 | m_lastAngularVelocity | ||
1124 | ); | ||
1125 | } | ||
1126 | else | ||
915 | { | 1127 | { |
916 | Vector3 dir = Vector3.One * Prim.ForceOrientation; | 1128 | // The vehicle is not adding anything angular wise. |
917 | float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1); | 1129 | VehicleRotationalVelocity = Vector3.Zero; |
918 | //Changes which way it banks in and out of turns | 1130 | VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); |
919 | |||
920 | //Use the square of the efficiency, as it looks much more how SL banking works | ||
921 | float effSquared = (m_bankingEfficiency*m_bankingEfficiency); | ||
922 | if (m_bankingEfficiency < 0) | ||
923 | effSquared *= -1; //Keep the negative! | ||
924 | |||
925 | float mix = Math.Abs(m_bankingMix); | ||
926 | if (m_angularMotorVelocity.X == 0) | ||
927 | { | ||
928 | /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f)) | ||
929 | { | ||
930 | Vector3 axisAngle; | ||
931 | float angle; | ||
932 | parent.Orientation.GetAxisAngle(out axisAngle, out angle); | ||
933 | Vector3 rotatedVel = parent.Velocity * parent.Orientation; | ||
934 | if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0)) | ||
935 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10; | ||
936 | else | ||
937 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10; | ||
938 | }*/ | ||
939 | } | ||
940 | else | ||
941 | banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4; | ||
942 | if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix) | ||
943 | //If they are colliding, we probably shouldn't shove the prim around... probably | ||
944 | { | ||
945 | float angVelZ = m_angularMotorVelocity.X*-1; | ||
946 | /*if(angVelZ > mix) | ||
947 | angVelZ = mix; | ||
948 | else if(angVelZ < -mix) | ||
949 | angVelZ = -mix;*/ | ||
950 | //This controls how fast and how far the banking occurs | ||
951 | Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0); | ||
952 | if (bankingRot.X > 3) | ||
953 | bankingRot.X = 3; | ||
954 | else if (bankingRot.X < -3) | ||
955 | bankingRot.X = -3; | ||
956 | bankingRot *= Prim.ForceOrientation; | ||
957 | banking += bankingRot; | ||
958 | } | ||
959 | m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency; | ||
960 | VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}", | ||
961 | Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking); | ||
962 | } | 1131 | } |
963 | 1132 | ||
964 | #endregion | 1133 | // ================================================================== |
965 | |||
966 | m_lastVertAttractor = vertattr; | ||
967 | |||
968 | // Sum velocities | ||
969 | m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection; | ||
970 | |||
971 | #region Linear Motor Offset | ||
972 | |||
973 | //Offset section | 1134 | //Offset section |
974 | if (m_linearMotorOffset != Vector3.Zero) | 1135 | if (m_linearMotorOffset != Vector3.Zero) |
975 | { | 1136 | { |
@@ -985,8 +1146,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
985 | // | 1146 | // |
986 | // The torque created is the linear velocity crossed with the offset | 1147 | // The torque created is the linear velocity crossed with the offset |
987 | 1148 | ||
988 | // NOTE: this computation does should be in the linear section | 1149 | // TODO: this computation should be in the linear section |
989 | // because there we know the impulse being applied. | 1150 | // because that is where we know the impulse being applied. |
990 | Vector3 torqueFromOffset = Vector3.Zero; | 1151 | Vector3 torqueFromOffset = Vector3.Zero; |
991 | // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); | 1152 | // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); |
992 | if (float.IsNaN(torqueFromOffset.X)) | 1153 | if (float.IsNaN(torqueFromOffset.X)) |
@@ -995,47 +1156,184 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
995 | torqueFromOffset.Y = 0; | 1156 | torqueFromOffset.Y = 0; |
996 | if (float.IsNaN(torqueFromOffset.Z)) | 1157 | if (float.IsNaN(torqueFromOffset.Z)) |
997 | torqueFromOffset.Z = 0; | 1158 | torqueFromOffset.Z = 0; |
998 | torqueFromOffset *= m_vehicleMass; | 1159 | |
999 | Prim.ApplyTorqueImpulse(torqueFromOffset, true); | 1160 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); |
1000 | VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); | 1161 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); |
1001 | } | 1162 | } |
1002 | 1163 | ||
1003 | #endregion | 1164 | } |
1165 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | ||
1166 | // Some vehicles, like boats, should always keep their up-side up. This can be done by | ||
1167 | // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to | ||
1168 | // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the | ||
1169 | // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency, | ||
1170 | // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An | ||
1171 | // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an | ||
1172 | // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. | ||
1173 | public Vector3 ComputeAngularVerticalAttraction() | ||
1174 | { | ||
1175 | Vector3 ret = Vector3.Zero; | ||
1004 | 1176 | ||
1005 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | 1177 | // If vertical attaction timescale is reasonable |
1178 | if (m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
1006 | { | 1179 | { |
1007 | m_lastAngularVelocity.X = 0; | 1180 | // Take a vector pointing up and convert it from world to vehicle relative coords. |
1008 | m_lastAngularVelocity.Y = 0; | 1181 | Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; |
1009 | VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | 1182 | |
1183 | // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) | ||
1184 | // is now: | ||
1185 | // leaning to one side: rotated around the X axis with the Y value going | ||
1186 | // from zero (nearly straight up) to one (completely to the side)) or | ||
1187 | // leaning front-to-back: rotated around the Y axis with the value of X being between | ||
1188 | // zero and one. | ||
1189 | // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. | ||
1190 | |||
1191 | // Y error means needed rotation around X axis and visa versa. | ||
1192 | // Since the error goes from zero to one, the asin is the corresponding angle. | ||
1193 | ret.X = (float)Math.Asin(verticalError.Y); | ||
1194 | // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) | ||
1195 | ret.Y = -(float)Math.Asin(verticalError.X); | ||
1196 | |||
1197 | // If verticalError.Z is negative, the vehicle is upside down. Add additional push. | ||
1198 | if (verticalError.Z < 0f) | ||
1199 | { | ||
1200 | ret.X += PIOverFour; | ||
1201 | ret.Y += PIOverFour; | ||
1202 | } | ||
1203 | |||
1204 | // 'ret' is now the necessary velocity to correct tilt in one second. | ||
1205 | // Correction happens over a number of seconds. | ||
1206 | Vector3 unscaledContrib = ret; | ||
1207 | ret /= m_verticalAttractionTimescale; | ||
1208 | |||
1209 | VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}", | ||
1210 | Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret); | ||
1010 | } | 1211 | } |
1212 | return ret; | ||
1213 | } | ||
1011 | 1214 | ||
1012 | if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | 1215 | // Return the angular correction to correct the direction the vehicle is pointing to be |
1216 | // the direction is should want to be pointing. | ||
1217 | // The vehicle is moving in some direction and correct its orientation to it is pointing | ||
1218 | // in that direction. | ||
1219 | // TODO: implement reference frame. | ||
1220 | public Vector3 ComputeAngularDeflection() | ||
1221 | { | ||
1222 | Vector3 ret = Vector3.Zero; | ||
1223 | return ret; // DEBUG DEBUG DEBUG | ||
1224 | // Disable angular deflection for the moment. | ||
1225 | // Since angularMotorUp and angularDeflection are computed independently, they will calculate | ||
1226 | // approximately the same X or Y correction. When added together (when contributions are combined) | ||
1227 | // this creates an over-correction and then wabbling as the target is overshot. | ||
1228 | // TODO: rethink how the different correction computations inter-relate. | ||
1229 | |||
1230 | if (m_angularDeflectionEfficiency != 0) | ||
1013 | { | 1231 | { |
1014 | m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. | 1232 | // The direction the vehicle is moving |
1015 | Prim.ZeroAngularMotion(true); | 1233 | Vector3 movingDirection = VehicleVelocity; |
1016 | VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | 1234 | movingDirection.Normalize(); |
1235 | |||
1236 | // The direction the vehicle is pointing | ||
1237 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; | ||
1238 | pointingDirection.Normalize(); | ||
1239 | |||
1240 | // The difference between what is and what should be. | ||
1241 | Vector3 deflectionError = movingDirection - pointingDirection; | ||
1242 | |||
1243 | // Don't try to correct very large errors (not our job) | ||
1244 | if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f; | ||
1245 | if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f; | ||
1246 | if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f; | ||
1247 | |||
1248 | // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); | ||
1249 | |||
1250 | // Scale the correction by recovery timescale and efficiency | ||
1251 | ret = (-deflectionError) * m_angularDeflectionEfficiency; | ||
1252 | ret /= m_angularDeflectionTimescale; | ||
1253 | |||
1254 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", | ||
1255 | Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret); | ||
1256 | VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", | ||
1257 | Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); | ||
1017 | } | 1258 | } |
1018 | else | 1259 | return ret; |
1260 | } | ||
1261 | |||
1262 | // Return an angular change to rotate the vehicle around the Z axis when the vehicle | ||
1263 | // is tipped around the X axis. | ||
1264 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | ||
1265 | // The vertical attractor feature must be enabled in order for the banking behavior to | ||
1266 | // function. The way banking works is this: a rotation around the vehicle's roll-axis will | ||
1267 | // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude | ||
1268 | // of the yaw effect will be proportional to the | ||
1269 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's | ||
1270 | // velocity along its preferred axis of motion. | ||
1271 | // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any | ||
1272 | // positive rotation (by the right-hand rule) about the roll-axis will effect a | ||
1273 | // (negative) torque around the yaw-axis, making it turn to the right--that is the | ||
1274 | // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. | ||
1275 | // Negating the banking coefficient will make it so that the vehicle leans to the | ||
1276 | // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). | ||
1277 | // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making | ||
1278 | // banking vehicles do what you want rather than what the laws of physics allow. | ||
1279 | // For example, consider a real motorcycle...it must be moving forward in order for | ||
1280 | // it to turn while banking, however video-game motorcycles are often configured | ||
1281 | // to turn in place when at a dead stop--because they are often easier to control | ||
1282 | // that way using the limited interface of the keyboard or game controller. The | ||
1283 | // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic | ||
1284 | // banking by functioning as a slider between a banking that is correspondingly | ||
1285 | // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the | ||
1286 | // banking effect depends only on the vehicle's rotation about its roll-axis compared | ||
1287 | // to "dynamic" where the banking is also proportional to its velocity along its | ||
1288 | // roll-axis. Finding the best value of the "mixture" will probably require trial and error. | ||
1289 | // The time it takes for the banking behavior to defeat a preexisting angular velocity about the | ||
1290 | // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to | ||
1291 | // bank quickly then give it a banking timescale of about a second or less, otherwise you can | ||
1292 | // make a sluggish vehicle by giving it a timescale of several seconds. | ||
1293 | public Vector3 ComputeAngularBanking() | ||
1294 | { | ||
1295 | Vector3 ret = Vector3.Zero; | ||
1296 | |||
1297 | if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
1019 | { | 1298 | { |
1020 | // Apply to the body. | 1299 | // This works by rotating a unit vector to the orientation of the vehicle. The |
1021 | // The above calculates the absolute angular velocity needed. Angular velocity is massless. | 1300 | // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt |
1022 | // Since we are stuffing the angular velocity directly into the object, the computed | 1301 | // up to one for full over). |
1023 | // velocity needs to be scaled by the timestep. | 1302 | Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation; |
1024 | Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity); | 1303 | |
1025 | Prim.ForceRotationalVelocity = applyAngularForce; | 1304 | // Figure out the yaw value for this much roll. |
1026 | 1305 | float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency; | |
1027 | // Decay the angular movement for next time | 1306 | // Keep the sign |
1028 | Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; | 1307 | if (rollComponents.Y < 0f) |
1029 | m_lastAngularVelocity *= Vector3.One - decayamount; | 1308 | turnComponent = -turnComponent; |
1030 | 1309 | ||
1031 | VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}", | 1310 | // TODO: there must be a better computation of the banking force. |
1032 | Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity); | 1311 | float bankingTurnForce = turnComponent; |
1312 | |||
1313 | // actual error = static turn error + dynamic turn error | ||
1314 | float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed; | ||
1315 | // TODO: the banking effect should not go to infinity but what to limit it to? | ||
1316 | mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f); | ||
1317 | |||
1318 | // Build the force vector to change rotation from what it is to what it should be | ||
1319 | ret.Z = -mixedBankingError; | ||
1320 | |||
1321 | // Don't do it all at once. | ||
1322 | ret /= m_bankingTimescale; | ||
1323 | |||
1324 | VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}", | ||
1325 | Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret); | ||
1033 | } | 1326 | } |
1034 | } //end MoveAngular | 1327 | return ret; |
1328 | } | ||
1035 | 1329 | ||
1330 | // This is from previous instantiations of XXXDynamics.cs. | ||
1331 | // Applies roll reference frame. | ||
1332 | // TODO: is this the right way to separate the code to do this operation? | ||
1333 | // Should this be in MoveAngular()? | ||
1036 | internal void LimitRotation(float timestep) | 1334 | internal void LimitRotation(float timestep) |
1037 | { | 1335 | { |
1038 | Quaternion rotq = Prim.ForceOrientation; | 1336 | Quaternion rotq = VehicleOrientation; |
1039 | Quaternion m_rot = rotq; | 1337 | Quaternion m_rot = rotq; |
1040 | if (m_RollreferenceFrame != Quaternion.Identity) | 1338 | if (m_RollreferenceFrame != Quaternion.Identity) |
1041 | { | 1339 | { |
@@ -1063,12 +1361,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1063 | } | 1361 | } |
1064 | if (rotq != m_rot) | 1362 | if (rotq != m_rot) |
1065 | { | 1363 | { |
1066 | Prim.ForceOrientation = m_rot; | 1364 | VehicleOrientation = m_rot; |
1067 | VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); | 1365 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); |
1068 | } | 1366 | } |
1069 | 1367 | ||
1070 | } | 1368 | } |
1071 | 1369 | ||
1370 | private float ClampInRange(float low, float val, float high) | ||
1371 | { | ||
1372 | return Math.Max(low, Math.Min(val, high)); | ||
1373 | // return Utils.Clamp(val, low, high); | ||
1374 | } | ||
1375 | |||
1072 | // Invoke the detailed logger and output something if it's enabled. | 1376 | // Invoke the detailed logger and output something if it's enabled. |
1073 | private void VDetailLog(string msg, params Object[] args) | 1377 | private void VDetailLog(string msg, params Object[] args) |
1074 | { | 1378 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 0df4310..756faed 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -32,6 +32,15 @@ using OMV = OpenMetaverse; | |||
32 | 32 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 33 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 34 | { |
35 | |||
36 | // A BSPrim can get individual information about its linkedness attached | ||
37 | // to it through an instance of a subclass of LinksetInfo. | ||
38 | // Each type of linkset will define the information needed for its type. | ||
39 | public abstract class BSLinksetInfo | ||
40 | { | ||
41 | public virtual void Clear() { } | ||
42 | } | ||
43 | |||
35 | public abstract class BSLinkset | 44 | public abstract class BSLinkset |
36 | { | 45 | { |
37 | // private static string LogHeader = "[BULLETSIM LINKSET]"; | 46 | // private static string LogHeader = "[BULLETSIM LINKSET]"; |
@@ -47,7 +56,7 @@ public abstract class BSLinkset | |||
47 | { | 56 | { |
48 | BSLinkset ret = null; | 57 | BSLinkset ret = null; |
49 | 58 | ||
50 | switch ((int)physScene.Params.linksetImplementation) | 59 | switch ((int)BSParam.LinksetImplementation) |
51 | { | 60 | { |
52 | case (int)LinksetImplementation.Constraint: | 61 | case (int)LinksetImplementation.Constraint: |
53 | ret = new BSLinksetConstraints(physScene, parent); | 62 | ret = new BSLinksetConstraints(physScene, parent); |
@@ -87,22 +96,8 @@ public abstract class BSLinkset | |||
87 | return BSPhysicsShapeType.SHAPE_UNKNOWN; | 96 | return BSPhysicsShapeType.SHAPE_UNKNOWN; |
88 | } | 97 | } |
89 | 98 | ||
90 | // Linksets move around the children so the linkset might need to compute the child position | ||
91 | public virtual OMV.Vector3 Position(BSPhysObject member) | ||
92 | { return member.RawPosition; } | ||
93 | public virtual OMV.Quaternion Orientation(BSPhysObject member) | ||
94 | { return member.RawOrientation; } | ||
95 | // TODO: does this need to be done for Velocity and RotationalVelocityy? | ||
96 | |||
97 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims | 99 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims |
98 | protected float m_mass; | 100 | public float LinksetMass { get; protected set; } |
99 | public float LinksetMass | ||
100 | { | ||
101 | get | ||
102 | { | ||
103 | return m_mass; | ||
104 | } | ||
105 | } | ||
106 | 101 | ||
107 | public virtual bool LinksetIsColliding { get { return false; } } | 102 | public virtual bool LinksetIsColliding { get { return false; } } |
108 | 103 | ||
@@ -116,7 +111,7 @@ public abstract class BSLinkset | |||
116 | get { return ComputeLinksetGeometricCenter(); } | 111 | get { return ComputeLinksetGeometricCenter(); } |
117 | } | 112 | } |
118 | 113 | ||
119 | protected void Initialize(BSScene scene, BSPhysObject parent) | 114 | protected BSLinkset(BSScene scene, BSPhysObject parent) |
120 | { | 115 | { |
121 | // A simple linkset of one (no children) | 116 | // A simple linkset of one (no children) |
122 | LinksetID = m_nextLinksetID++; | 117 | LinksetID = m_nextLinksetID++; |
@@ -126,7 +121,8 @@ public abstract class BSLinkset | |||
126 | PhysicsScene = scene; | 121 | PhysicsScene = scene; |
127 | LinksetRoot = parent; | 122 | LinksetRoot = parent; |
128 | m_children = new HashSet<BSPhysObject>(); | 123 | m_children = new HashSet<BSPhysObject>(); |
129 | m_mass = parent.RawMass; | 124 | LinksetMass = parent.RawMass; |
125 | Rebuilding = false; | ||
130 | } | 126 | } |
131 | 127 | ||
132 | // Link to a linkset where the child knows the parent. | 128 | // Link to a linkset where the child knows the parent. |
@@ -140,7 +136,7 @@ public abstract class BSLinkset | |||
140 | // Don't add the root to its own linkset | 136 | // Don't add the root to its own linkset |
141 | if (!IsRoot(child)) | 137 | if (!IsRoot(child)) |
142 | AddChildToLinkset(child); | 138 | AddChildToLinkset(child); |
143 | m_mass = ComputeLinksetMass(); | 139 | LinksetMass = ComputeLinksetMass(); |
144 | } | 140 | } |
145 | return this; | 141 | return this; |
146 | } | 142 | } |
@@ -159,7 +155,7 @@ public abstract class BSLinkset | |||
159 | return this; | 155 | return this; |
160 | } | 156 | } |
161 | RemoveChildFromLinkset(child); | 157 | RemoveChildFromLinkset(child); |
162 | m_mass = ComputeLinksetMass(); | 158 | LinksetMass = ComputeLinksetMass(); |
163 | } | 159 | } |
164 | 160 | ||
165 | // The child is down to a linkset of just itself | 161 | // The child is down to a linkset of just itself |
@@ -219,7 +215,7 @@ public abstract class BSLinkset | |||
219 | // I am the root of a linkset and a new child is being added | 215 | // I am the root of a linkset and a new child is being added |
220 | // Called while LinkActivity is locked. | 216 | // Called while LinkActivity is locked. |
221 | protected abstract void AddChildToLinkset(BSPhysObject child); | 217 | protected abstract void AddChildToLinkset(BSPhysObject child); |
222 | 218 | ||
223 | // I am the root of a linkset and one of my children is being removed. | 219 | // I am the root of a linkset and one of my children is being removed. |
224 | // Safe to call even if the child is not really in my linkset. | 220 | // Safe to call even if the child is not really in my linkset. |
225 | protected abstract void RemoveChildFromLinkset(BSPhysObject child); | 221 | protected abstract void RemoveChildFromLinkset(BSPhysObject child); |
@@ -227,7 +223,14 @@ public abstract class BSLinkset | |||
227 | // When physical properties are changed the linkset needs to recalculate | 223 | // When physical properties are changed the linkset needs to recalculate |
228 | // its internal properties. | 224 | // its internal properties. |
229 | // May be called at runtime or taint-time. | 225 | // May be called at runtime or taint-time. |
230 | public abstract void Refresh(BSPhysObject requestor); | 226 | public virtual void Refresh(BSPhysObject requestor) |
227 | { | ||
228 | LinksetMass = ComputeLinksetMass(); | ||
229 | } | ||
230 | |||
231 | // Flag denoting the linkset is in the process of being rebuilt. | ||
232 | // Used to know not the schedule a rebuild in the middle of a rebuild. | ||
233 | protected bool Rebuilding { get; set; } | ||
231 | 234 | ||
232 | // The object is going dynamic (physical). Do any setup necessary | 235 | // The object is going dynamic (physical). Do any setup necessary |
233 | // for a dynamic linkset. | 236 | // for a dynamic linkset. |
@@ -245,8 +248,9 @@ public abstract class BSLinkset | |||
245 | 248 | ||
246 | // Called when a parameter update comes from the physics engine for any object | 249 | // Called when a parameter update comes from the physics engine for any object |
247 | // of the linkset is received. | 250 | // of the linkset is received. |
251 | // Passed flag is update came from physics engine (true) or the user (false). | ||
248 | // Called at taint-time!! | 252 | // Called at taint-time!! |
249 | public abstract void UpdateProperties(BSPhysObject physObject); | 253 | public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate); |
250 | 254 | ||
251 | // Routine used when rebuilding the body of the root of the linkset | 255 | // Routine used when rebuilding the body of the root of the linkset |
252 | // Destroy all the constraints have have been made to root. | 256 | // Destroy all the constraints have have been made to root. |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index b9c2cf9..bd03d31 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -28,22 +28,54 @@ using System; | |||
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Text; | 29 | using System.Text; |
30 | 30 | ||
31 | using OpenSim.Framework; | ||
32 | |||
31 | using OMV = OpenMetaverse; | 33 | using OMV = OpenMetaverse; |
32 | 34 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 36 | { |
37 | |||
38 | // When a child is linked, the relationship position of the child to the parent | ||
39 | // is remembered so the child's world position can be recomputed when it is | ||
40 | // removed from the linkset. | ||
41 | sealed class BSLinksetCompoundInfo : BSLinksetInfo | ||
42 | { | ||
43 | public OMV.Vector3 OffsetPos; | ||
44 | public OMV.Quaternion OffsetRot; | ||
45 | public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r) | ||
46 | { | ||
47 | OffsetPos = p; | ||
48 | OffsetRot = r; | ||
49 | } | ||
50 | public override void Clear() | ||
51 | { | ||
52 | OffsetPos = OMV.Vector3.Zero; | ||
53 | OffsetRot = OMV.Quaternion.Identity; | ||
54 | } | ||
55 | public override string ToString() | ||
56 | { | ||
57 | StringBuilder buff = new StringBuilder(); | ||
58 | buff.Append("<p="); | ||
59 | buff.Append(OffsetPos.ToString()); | ||
60 | buff.Append(",r="); | ||
61 | buff.Append(OffsetRot.ToString()); | ||
62 | buff.Append(">"); | ||
63 | return buff.ToString(); | ||
64 | } | ||
65 | }; | ||
66 | |||
35 | public sealed class BSLinksetCompound : BSLinkset | 67 | public sealed class BSLinksetCompound : BSLinkset |
36 | { | 68 | { |
37 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; | 69 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; |
38 | 70 | ||
39 | public BSLinksetCompound(BSScene scene, BSPhysObject parent) | 71 | public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent) |
40 | { | 72 | { |
41 | base.Initialize(scene, parent); | ||
42 | } | 73 | } |
43 | 74 | ||
44 | // For compound implimented linksets, if there are children, use compound shape for the root. | 75 | // For compound implimented linksets, if there are children, use compound shape for the root. |
45 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | 76 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) |
46 | { | 77 | { |
78 | // Returning 'unknown' means we don't have a preference. | ||
47 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | 79 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; |
48 | if (IsRoot(requestor) && HasAnyChildren) | 80 | if (IsRoot(requestor) && HasAnyChildren) |
49 | { | 81 | { |
@@ -55,27 +87,33 @@ public sealed class BSLinksetCompound : BSLinkset | |||
55 | 87 | ||
56 | // When physical properties are changed the linkset needs to recalculate | 88 | // When physical properties are changed the linkset needs to recalculate |
57 | // its internal properties. | 89 | // its internal properties. |
58 | // This is queued in the 'post taint' queue so the | ||
59 | // refresh will happen once after all the other taints are applied. | ||
60 | public override void Refresh(BSPhysObject requestor) | 90 | public override void Refresh(BSPhysObject requestor) |
61 | { | 91 | { |
62 | // External request for Refresh (from BSPrim) is not necessary | 92 | base.Refresh(requestor); |
63 | // InternalRefresh(requestor); | 93 | |
94 | // Something changed so do the rebuilding thing | ||
95 | // ScheduleRebuild(); | ||
64 | } | 96 | } |
65 | 97 | ||
66 | private void InternalRefresh(BSPhysObject requestor) | 98 | // Schedule a refresh to happen after all the other taint processing. |
99 | private void ScheduleRebuild(BSPhysObject requestor) | ||
67 | { | 100 | { |
68 | DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); | 101 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2}", |
69 | // Queue to happen after all the other taint processing | 102 | requestor.LocalID, Rebuilding, HasAnyChildren); |
70 | PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() | 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 | if (!Rebuilding && HasAnyChildren) | ||
71 | { | 107 | { |
72 | if (IsRoot(requestor) && HasAnyChildren) | 108 | PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() |
73 | RecomputeLinksetCompound(); | 109 | { |
74 | }); | 110 | if (HasAnyChildren) |
111 | RecomputeLinksetCompound(); | ||
112 | }); | ||
113 | } | ||
75 | } | 114 | } |
76 | 115 | ||
77 | // The object is going dynamic (physical). Do any setup necessary | 116 | // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset. |
78 | // for a dynamic linkset. | ||
79 | // Only the state of the passed object can be modified. The rest of the linkset | 117 | // Only the state of the passed object can be modified. The rest of the linkset |
80 | // has not yet been fully constructed. | 118 | // has not yet been fully constructed. |
81 | // Return 'true' if any properties updated on the passed object. | 119 | // Return 'true' if any properties updated on the passed object. |
@@ -84,12 +122,22 @@ public sealed class BSLinksetCompound : BSLinkset | |||
84 | { | 122 | { |
85 | bool ret = false; | 123 | bool ret = false; |
86 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 124 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
87 | if (!IsRoot(child)) | 125 | if (IsRoot(child)) |
126 | { | ||
127 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. | ||
128 | ScheduleRebuild(LinksetRoot); | ||
129 | } | ||
130 | else | ||
88 | { | 131 | { |
89 | // Physical children are removed from the world as the shape ofthe root compound | 132 | // The origional prims are removed from the world as the shape of the root compound |
90 | // shape takes over. | 133 | // shape takes over. |
91 | BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 134 | PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
92 | BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | 135 | PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION); |
136 | // We don't want collisions from the old linkset children. | ||
137 | PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
138 | |||
139 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
140 | |||
93 | ret = true; | 141 | ret = true; |
94 | } | 142 | } |
95 | return ret; | 143 | return ret; |
@@ -104,33 +152,39 @@ public sealed class BSLinksetCompound : BSLinkset | |||
104 | { | 152 | { |
105 | bool ret = false; | 153 | bool ret = false; |
106 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 154 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
107 | if (!IsRoot(child)) | 155 | if (IsRoot(child)) |
156 | { | ||
157 | ScheduleRebuild(LinksetRoot); | ||
158 | } | ||
159 | else | ||
108 | { | 160 | { |
109 | // The non-physical children can come back to life. | 161 | // The non-physical children can come back to life. |
110 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 162 | PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
111 | // Don't force activation so setting of DISABLE_SIMULATION can stay. | 163 | |
112 | BulletSimAPI.Activate2(child.PhysBody.ptr, false); | 164 | child.PhysBody.collisionType = CollisionType.LinksetChild; |
165 | |||
166 | // Don't force activation so setting of DISABLE_SIMULATION can stay if used. | ||
167 | PhysicsScene.PE.Activate(child.PhysBody, false); | ||
113 | ret = true; | 168 | ret = true; |
114 | } | 169 | } |
115 | return ret; | 170 | return ret; |
116 | } | 171 | } |
117 | 172 | ||
118 | // Called at taint-time!! | 173 | public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate) |
119 | public override void UpdateProperties(BSPhysObject updated) | ||
120 | { | ||
121 | // Nothing to do for constraints on property updates | ||
122 | } | ||
123 | |||
124 | // The children move around in relationship to the root. | ||
125 | // Just grab the current values of wherever it is right now. | ||
126 | public override OMV.Vector3 Position(BSPhysObject member) | ||
127 | { | ||
128 | return BulletSimAPI.GetPosition2(member.PhysBody.ptr); | ||
129 | } | ||
130 | |||
131 | public override OMV.Quaternion Orientation(BSPhysObject member) | ||
132 | { | 174 | { |
133 | return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); | 175 | // The user moving a child around requires the rebuilding of the linkset compound shape |
176 | // One problem is this happens when a border is crossed -- the simulator implementation | ||
177 | // is to store the position into the group which causes the move of the object | ||
178 | // but it also means all the child positions get updated. | ||
179 | // What would cause an unnecessary rebuild so we make sure the linkset is in a | ||
180 | // region before bothering to do a rebuild. | ||
181 | if (!IsRoot(updated) | ||
182 | && !physicalUpdate | ||
183 | && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) | ||
184 | { | ||
185 | updated.LinksetInfo = null; | ||
186 | ScheduleRebuild(updated); | ||
187 | } | ||
134 | } | 188 | } |
135 | 189 | ||
136 | // Routine called when rebuilding the body of some member of the linkset. | 190 | // Routine called when rebuilding the body of some member of the linkset. |
@@ -142,24 +196,62 @@ public sealed class BSLinksetCompound : BSLinkset | |||
142 | bool ret = false; | 196 | bool ret = false; |
143 | 197 | ||
144 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", | 198 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", |
145 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child)); | 199 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, IsRoot(child)); |
146 | 200 | ||
147 | if (!IsRoot(child)) | 201 | if (!IsRoot(child)) |
148 | { | 202 | { |
149 | // Cause the current shape to be freed and the new one to be built. | 203 | // Because it is a convenient time, recompute child world position and rotation based on |
150 | InternalRefresh(LinksetRoot); | 204 | // its position in the linkset. |
151 | ret = true; | 205 | RecomputeChildWorldPosition(child, true); |
152 | } | 206 | } |
153 | 207 | ||
208 | // Cannot schedule a refresh/rebuild here because this routine is called when | ||
209 | // the linkset is being rebuilt. | ||
210 | // InternalRefresh(LinksetRoot); | ||
211 | |||
154 | return ret; | 212 | return ret; |
155 | } | 213 | } |
156 | 214 | ||
157 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | 215 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', |
158 | // this routine will restore the removed constraints. | 216 | // this routine will restore the removed constraints. |
159 | // Called at taint-time!! | 217 | // Called at taint-time!! |
160 | public override void RestoreBodyDependencies(BSPrim child) | 218 | public override void RestoreBodyDependencies(BSPrim child) |
161 | { | 219 | { |
162 | // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. | 220 | } |
221 | |||
222 | // When the linkset is built, the child shape is added to the compound shape relative to the | ||
223 | // root shape. The linkset then moves around but this does not move the actual child | ||
224 | // prim. The child prim's location must be recomputed based on the location of the root shape. | ||
225 | private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime) | ||
226 | { | ||
227 | BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo; | ||
228 | if (lci != null) | ||
229 | { | ||
230 | if (inTaintTime) | ||
231 | { | ||
232 | OMV.Vector3 oldPos = child.RawPosition; | ||
233 | child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos; | ||
234 | child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
235 | DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}", | ||
236 | child.LocalID, oldPos, lci, child.RawPosition); | ||
237 | } | ||
238 | else | ||
239 | { | ||
240 | // TaintedObject is not used here so the raw position is set now and not at taint-time. | ||
241 | child.Position = LinksetRoot.RawPosition + lci.OffsetPos; | ||
242 | child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
243 | } | ||
244 | } | ||
245 | else | ||
246 | { | ||
247 | // This happens when children have been added to the linkset but the linkset | ||
248 | // has not been constructed yet. So like, at taint time, adding children to a linkset | ||
249 | // and then changing properties of the children (makePhysical, for instance) | ||
250 | // but the post-print action of actually rebuilding the linkset has not yet happened. | ||
251 | // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}", | ||
252 | // LogHeader, child.LocalID); | ||
253 | DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID); | ||
254 | } | ||
163 | } | 255 | } |
164 | 256 | ||
165 | // ================================================================ | 257 | // ================================================================ |
@@ -174,24 +266,25 @@ public sealed class BSLinksetCompound : BSLinkset | |||
174 | 266 | ||
175 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | 267 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); |
176 | 268 | ||
177 | // Cause constraints and assorted properties to be recomputed before the next simulation step. | 269 | // Rebuild the compound shape with the new child shape included |
178 | InternalRefresh(LinksetRoot); | 270 | ScheduleRebuild(child); |
179 | } | 271 | } |
180 | return; | 272 | return; |
181 | } | 273 | } |
182 | 274 | ||
183 | // Remove the specified child from the linkset. | 275 | // Remove the specified child from the linkset. |
184 | // Safe to call even if the child is not really in my linkset. | 276 | // Safe to call even if the child is not really in the linkset. |
185 | protected override void RemoveChildFromLinkset(BSPhysObject child) | 277 | protected override void RemoveChildFromLinkset(BSPhysObject child) |
186 | { | 278 | { |
187 | if (m_children.Remove(child)) | 279 | if (m_children.Remove(child)) |
188 | { | 280 | { |
189 | DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | 281 | DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", |
190 | child.LocalID, | 282 | child.LocalID, |
191 | LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), | 283 | LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, |
192 | child.LocalID, child.PhysBody.ptr.ToString("X")); | 284 | child.LocalID, child.PhysBody.AddrString); |
193 | 285 | ||
194 | // Cause the child's body to be rebuilt and thus restored to normal operation | 286 | // Cause the child's body to be rebuilt and thus restored to normal operation |
287 | RecomputeChildWorldPosition(child, false); | ||
195 | child.ForceBodyShapeRebuild(false); | 288 | child.ForceBodyShapeRebuild(false); |
196 | 289 | ||
197 | if (!HasAnyChildren) | 290 | if (!HasAnyChildren) |
@@ -201,8 +294,8 @@ public sealed class BSLinksetCompound : BSLinkset | |||
201 | } | 294 | } |
202 | else | 295 | else |
203 | { | 296 | { |
204 | // Schedule a rebuild of the linkset before the next simulation tick. | 297 | // Rebuild the compound shape with the child removed |
205 | InternalRefresh(LinksetRoot); | 298 | ScheduleRebuild(child); |
206 | } | 299 | } |
207 | } | 300 | } |
208 | return; | 301 | return; |
@@ -215,61 +308,85 @@ public sealed class BSLinksetCompound : BSLinkset | |||
215 | // Called at taint time!! | 308 | // Called at taint time!! |
216 | private void RecomputeLinksetCompound() | 309 | private void RecomputeLinksetCompound() |
217 | { | 310 | { |
218 | // Cause the root shape to be rebuilt as a compound object with just the root in it | 311 | try |
219 | LinksetRoot.ForceBodyShapeRebuild(true); | ||
220 | |||
221 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | ||
222 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | ||
223 | |||
224 | // Add a shape for each of the other children in the linkset | ||
225 | ForEachMember(delegate(BSPhysObject cPrim) | ||
226 | { | 312 | { |
227 | if (!IsRoot(cPrim)) | 313 | // Suppress rebuilding while rebuilding |
228 | { | 314 | Rebuilding = true; |
229 | // Each child position and rotation is given relative to the root. | ||
230 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | ||
231 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | ||
232 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | ||
233 | 315 | ||
234 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", | 316 | // Cause the root shape to be rebuilt as a compound object with just the root in it |
235 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); | 317 | LinksetRoot.ForceBodyShapeRebuild(true); |
236 | 318 | ||
237 | if (cPrim.PhysShape.isNativeShape) | 319 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", |
238 | { | 320 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); |
239 | // Native shapes are not shared so we need to create a new one. | 321 | |
240 | // A mesh or hull is created because scale is not available on a native shape. | 322 | // Add a shape for each of the other children in the linkset |
241 | // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?) | 323 | ForEachMember(delegate(BSPhysObject cPrim) |
242 | BulletShape saveShape = cPrim.PhysShape; | 324 | { |
243 | cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape | 325 | if (!IsRoot(cPrim)) |
244 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | ||
245 | BulletShape newShape = cPrim.PhysShape; | ||
246 | cPrim.PhysShape = saveShape; | ||
247 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot); | ||
248 | } | ||
249 | else | ||
250 | { | 326 | { |
251 | // For the shared shapes (meshes and hulls), just use the shape in the child. | 327 | // Compute the displacement of the child from the root of the linkset. |
252 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | 328 | // This info is saved in the child prim so the relationship does not |
329 | // change over time and the new child position can be computed | ||
330 | // when the linkset is being disassembled (the linkset may have moved). | ||
331 | BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo; | ||
332 | if (lci == null) | ||
253 | { | 333 | { |
254 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | 334 | // Each child position and rotation is given relative to the root. |
255 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | 335 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); |
336 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | ||
337 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | ||
338 | |||
339 | // Save relative position for recomputing child's world position after moving linkset. | ||
340 | lci = new BSLinksetCompoundInfo(displacementPos, displacementRot); | ||
341 | cPrim.LinksetInfo = lci; | ||
342 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci); | ||
256 | } | 343 | } |
257 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot); | ||
258 | } | ||
259 | } | ||
260 | return false; // 'false' says to move onto the next child in the list | ||
261 | }); | ||
262 | 344 | ||
263 | // With all of the linkset packed into the root prim, it has the mass of everyone. | 345 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", |
264 | float linksetMass = LinksetMass; | 346 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot); |
265 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass); | ||
266 | 347 | ||
267 | BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); | 348 | if (cPrim.PhysShape.isNativeShape) |
349 | { | ||
350 | // A native shape is turning into a hull collision shape because native | ||
351 | // shapes are not shared so we have to hullify it so it will be tracked | ||
352 | // and freed at the correct time. This also solves the scaling problem | ||
353 | // (native shapes scaled but hull/meshes are assumed to not be). | ||
354 | // TODO: decide of the native shape can just be used in the compound shape. | ||
355 | // Use call to CreateGeomNonSpecial(). | ||
356 | BulletShape saveShape = cPrim.PhysShape; | ||
357 | cPrim.PhysShape.Clear(); // Don't let the create free the child's shape | ||
358 | // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null); | ||
359 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | ||
360 | BulletShape newShape = cPrim.PhysShape; | ||
361 | cPrim.PhysShape = saveShape; | ||
362 | PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, lci.OffsetPos, lci.OffsetRot); | ||
363 | } | ||
364 | else | ||
365 | { | ||
366 | // For the shared shapes (meshes and hulls), just use the shape in the child. | ||
367 | // The reference count added here will be decremented when the compound shape | ||
368 | // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced). | ||
369 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | ||
370 | { | ||
371 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | ||
372 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | ||
373 | } | ||
374 | PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot); | ||
375 | } | ||
376 | } | ||
377 | return false; // 'false' says to move onto the next child in the list | ||
378 | }); | ||
268 | 379 | ||
269 | // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets. | 380 | // With all of the linkset packed into the root prim, it has the mass of everyone. |
270 | // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, | 381 | LinksetMass = ComputeLinksetMass(); |
271 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); | 382 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); |
383 | } | ||
384 | finally | ||
385 | { | ||
386 | Rebuilding = false; | ||
387 | } | ||
272 | 388 | ||
389 | PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); | ||
273 | } | 390 | } |
274 | } | 391 | } |
275 | } \ No newline at end of file | 392 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index c855fda..d0b2a56 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs | |||
@@ -36,9 +36,8 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
36 | { | 36 | { |
37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; | 37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; |
38 | 38 | ||
39 | public BSLinksetConstraints(BSScene scene, BSPhysObject parent) | 39 | public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent) |
40 | { | 40 | { |
41 | base.Initialize(scene, parent); | ||
42 | } | 41 | } |
43 | 42 | ||
44 | // When physical properties are changed the linkset needs to recalculate | 43 | // When physical properties are changed the linkset needs to recalculate |
@@ -47,12 +46,17 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
47 | // refresh will happen once after all the other taints are applied. | 46 | // refresh will happen once after all the other taints are applied. |
48 | public override void Refresh(BSPhysObject requestor) | 47 | public override void Refresh(BSPhysObject requestor) |
49 | { | 48 | { |
50 | // Queue to happen after all the other taint processing | 49 | base.Refresh(requestor); |
51 | PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() | 50 | |
52 | { | 51 | if (HasAnyChildren && IsRoot(requestor)) |
53 | if (HasAnyChildren && IsRoot(requestor)) | 52 | { |
54 | RecomputeLinksetConstraints(); | 53 | // Queue to happen after all the other taint processing |
55 | }); | 54 | PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() |
55 | { | ||
56 | if (HasAnyChildren && IsRoot(requestor)) | ||
57 | RecomputeLinksetConstraints(); | ||
58 | }); | ||
59 | } | ||
56 | } | 60 | } |
57 | 61 | ||
58 | // The object is going dynamic (physical). Do any setup necessary | 62 | // The object is going dynamic (physical). Do any setup necessary |
@@ -79,23 +83,11 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
79 | } | 83 | } |
80 | 84 | ||
81 | // Called at taint-time!! | 85 | // Called at taint-time!! |
82 | public override void UpdateProperties(BSPhysObject updated) | 86 | public override void UpdateProperties(BSPhysObject updated, bool inTaintTime) |
83 | { | 87 | { |
84 | // Nothing to do for constraints on property updates | 88 | // Nothing to do for constraints on property updates |
85 | } | 89 | } |
86 | 90 | ||
87 | // The children of the linkset are moved around by the constraints. | ||
88 | // Just grab the current values of wherever it is right now. | ||
89 | public override OMV.Vector3 Position(BSPhysObject member) | ||
90 | { | ||
91 | return BulletSimAPI.GetPosition2(member.PhysBody.ptr); | ||
92 | } | ||
93 | |||
94 | public override OMV.Quaternion Orientation(BSPhysObject member) | ||
95 | { | ||
96 | return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); | ||
97 | } | ||
98 | |||
99 | // Routine called when rebuilding the body of some member of the linkset. | 91 | // Routine called when rebuilding the body of some member of the linkset. |
100 | // Destroy all the constraints have have been made to root and set | 92 | // Destroy all the constraints have have been made to root and set |
101 | // up to rebuild the constraints before the next simulation step. | 93 | // up to rebuild the constraints before the next simulation step. |
@@ -106,7 +98,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
106 | bool ret = false; | 98 | bool ret = false; |
107 | 99 | ||
108 | DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", | 100 | DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", |
109 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X")); | 101 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); |
110 | 102 | ||
111 | lock (m_linksetActivityLock) | 103 | lock (m_linksetActivityLock) |
112 | { | 104 | { |
@@ -155,8 +147,8 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
155 | 147 | ||
156 | DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | 148 | DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", |
157 | childx.LocalID, | 149 | childx.LocalID, |
158 | rootx.LocalID, rootx.PhysBody.ptr.ToString("X"), | 150 | rootx.LocalID, rootx.PhysBody.AddrString, |
159 | childx.LocalID, childx.PhysBody.ptr.ToString("X")); | 151 | childx.LocalID, childx.PhysBody.AddrString); |
160 | 152 | ||
161 | PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() | 153 | PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() |
162 | { | 154 | { |
@@ -195,8 +187,8 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
195 | 187 | ||
196 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", | 188 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", |
197 | rootPrim.LocalID, | 189 | rootPrim.LocalID, |
198 | rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), | 190 | rootPrim.LocalID, rootPrim.PhysBody.AddrString, |
199 | childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"), | 191 | childPrim.LocalID, childPrim.PhysBody.AddrString, |
200 | rootPrim.Position, childPrim.Position, midPoint); | 192 | rootPrim.Position, childPrim.Position, midPoint); |
201 | 193 | ||
202 | // create a constraint that allows no freedom of movement between the two objects | 194 | // create a constraint that allows no freedom of movement between the two objects |
@@ -239,14 +231,14 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
239 | constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | 231 | constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); |
240 | 232 | ||
241 | // tweek the constraint to increase stability | 233 | // tweek the constraint to increase stability |
242 | constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset)); | 234 | constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset)); |
243 | constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor), | 235 | constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor), |
244 | PhysicsScene.Params.linkConstraintTransMotorMaxVel, | 236 | BSParam.LinkConstraintTransMotorMaxVel, |
245 | PhysicsScene.Params.linkConstraintTransMotorMaxForce); | 237 | BSParam.LinkConstraintTransMotorMaxForce); |
246 | constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); | 238 | constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP); |
247 | if (PhysicsScene.Params.linkConstraintSolverIterations != 0f) | 239 | if (BSParam.LinkConstraintSolverIterations != 0f) |
248 | { | 240 | { |
249 | constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); | 241 | constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations); |
250 | } | 242 | } |
251 | return constrain; | 243 | return constrain; |
252 | } | 244 | } |
@@ -260,14 +252,14 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
260 | bool ret = false; | 252 | bool ret = false; |
261 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", | 253 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", |
262 | rootPrim.LocalID, | 254 | rootPrim.LocalID, |
263 | rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), | 255 | rootPrim.LocalID, rootPrim.PhysBody.AddrString, |
264 | childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X")); | 256 | childPrim.LocalID, childPrim.PhysBody.AddrString); |
265 | 257 | ||
266 | // Find the constraint for this link and get rid of it from the overall collection and from my list | 258 | // Find the constraint for this link and get rid of it from the overall collection and from my list |
267 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) | 259 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) |
268 | { | 260 | { |
269 | // Make the child refresh its location | 261 | // Make the child refresh its location |
270 | BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr); | 262 | PhysicsScene.PE.PushUpdate(childPrim.PhysBody); |
271 | ret = true; | 263 | ret = true; |
272 | } | 264 | } |
273 | 265 | ||
@@ -292,20 +284,17 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
292 | private void RecomputeLinksetConstraints() | 284 | private void RecomputeLinksetConstraints() |
293 | { | 285 | { |
294 | float linksetMass = LinksetMass; | 286 | float linksetMass = LinksetMass; |
295 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass); | 287 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true); |
296 | 288 | ||
297 | // DEBUG: see of inter-linkset collisions are causing problems | ||
298 | // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, | ||
299 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); | ||
300 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", | 289 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", |
301 | LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), linksetMass); | 290 | LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); |
302 | 291 | ||
303 | foreach (BSPhysObject child in m_children) | 292 | foreach (BSPhysObject child in m_children) |
304 | { | 293 | { |
305 | // A child in the linkset physically shows the mass of the whole linkset. | 294 | // A child in the linkset physically shows the mass of the whole linkset. |
306 | // This allows Bullet to apply enough force on the child to move the whole linkset. | 295 | // This allows Bullet to apply enough force on the child to move the whole linkset. |
307 | // (Also do the mass stuff before recomputing the constraint so mass is not zero.) | 296 | // (Also do the mass stuff before recomputing the constraint so mass is not zero.) |
308 | child.UpdatePhysicalMassProperties(linksetMass); | 297 | child.UpdatePhysicalMassProperties(linksetMass, true); |
309 | 298 | ||
310 | BSConstraint constrain; | 299 | BSConstraint constrain; |
311 | if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) | 300 | if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) |
@@ -315,11 +304,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
315 | } | 304 | } |
316 | constrain.RecomputeConstraintVariables(linksetMass); | 305 | constrain.RecomputeConstraintVariables(linksetMass); |
317 | 306 | ||
318 | // DEBUG: see of inter-linkset collisions are causing problems | 307 | // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG |
319 | // BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr, | ||
320 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); | ||
321 | |||
322 | // BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG | ||
323 | } | 308 | } |
324 | 309 | ||
325 | } | 310 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs new file mode 100755 index 0000000..92d62ff --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs | |||
@@ -0,0 +1,200 @@ | |||
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 | MaterialAttributes thisAttrib = Attributes[matType]; | ||
184 | FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); | ||
185 | if (fieldInfo != null) | ||
186 | { | ||
187 | fieldInfo.SetValue(thisAttrib, val); | ||
188 | Attributes[matType] = thisAttrib; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | // Given a material type, return a structure of attributes. | ||
193 | public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) | ||
194 | { | ||
195 | int ind = (int)type; | ||
196 | if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; | ||
197 | return Attributes[ind]; | ||
198 | } | ||
199 | } | ||
200 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index bc6e4c4..6d0db2e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | |||
@@ -1,104 +1,467 @@ | |||
1 | using System; | 1 | /* |
2 | using System.Collections.Generic; | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | using System.Text; | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | using OpenMetaverse; | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without | |
6 | namespace OpenSim.Region.Physics.BulletSPlugin | 6 | * modification, are permitted provided that the following conditions are met: |
7 | { | 7 | * * Redistributions of source code must retain the above copyright |
8 | public abstract class BSMotor | 8 | * notice, this list of conditions and the following disclaimer. |
9 | { | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | public virtual void Reset() { } | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | public virtual void Zero() { } | 11 | * documentation and/or other materials provided with the distribution. |
12 | } | 12 | * * Neither the name of the OpenSimulator Project nor the |
13 | // Can all the incremental stepping be replaced with motor classes? | 13 | * names of its contributors may be used to endorse or promote products |
14 | public class BSVMotor : BSMotor | 14 | * derived from this software without specific prior written permission. |
15 | { | 15 | * |
16 | public Vector3 FrameOfReference { get; set; } | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | public Vector3 Offset { get; set; } | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
19 | public float TimeScale { get; set; } | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | public float TargetValueDecayTimeScale { get; set; } | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | public Vector3 CurrentValueReductionTimescale { get; set; } | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | public float Efficiency { get; set; } | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
24 | public Vector3 TargetValue { get; private set; } | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | public Vector3 CurrentValue { get; private set; } | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | 26 | * | |
27 | 27 | */ | |
28 | 28 | using System; | |
29 | BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) | 29 | using System.Collections.Generic; |
30 | { | 30 | using System.Text; |
31 | TimeScale = timeScale; | 31 | using OpenMetaverse; |
32 | TargetValueDecayTimeScale = decayTimeScale; | 32 | using OpenSim.Framework; |
33 | CurrentValueReductionTimescale = frictionTimeScale; | 33 | |
34 | Efficiency = efficiency; | 34 | namespace OpenSim.Region.Physics.BulletSPlugin |
35 | } | 35 | { |
36 | public void SetCurrent(Vector3 current) | 36 | public abstract class BSMotor |
37 | { | 37 | { |
38 | CurrentValue = current; | 38 | // Timescales and other things can be turned off by setting them to 'infinite'. |
39 | } | 39 | public const float Infinite = 12345.6f; |
40 | public void SetTarget(Vector3 target) | 40 | public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite); |
41 | { | 41 | |
42 | TargetValue = target; | 42 | public BSMotor(string useName) |
43 | } | 43 | { |
44 | public Vector3 Step(float timeStep) | 44 | UseName = useName; |
45 | { | 45 | PhysicsScene = null; |
46 | if (CurrentValue.LengthSquared() > 0.001f) | 46 | Enabled = true; |
47 | { | 47 | } |
48 | // Vector3 origDir = Target; // DEBUG | 48 | public virtual bool Enabled { get; set; } |
49 | // Vector3 origVel = CurrentValue; // DEBUG | 49 | public virtual void Reset() { } |
50 | 50 | public virtual void Zero() { } | |
51 | // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete | 51 | public virtual void GenerateTestOutput(float timeStep) { } |
52 | Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep; | 52 | |
53 | CurrentValue += addAmount; | 53 | // A name passed at motor creation for easily identifyable debugging messages. |
54 | 54 | public string UseName { get; private set; } | |
55 | float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | 55 | |
56 | TargetValue *= (1f - decayFactor); | 56 | // Used only for outputting debug information. Might not be set so check for null. |
57 | 57 | public BSScene PhysicsScene { get; set; } | |
58 | Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep; | 58 | protected void MDetailLog(string msg, params Object[] parms) |
59 | CurrentValue *= (Vector3.One - frictionFactor); | 59 | { |
60 | } | 60 | if (PhysicsScene != null) |
61 | else | 61 | { |
62 | { | 62 | PhysicsScene.DetailLog(msg, parms); |
63 | // if what remains of direction is very small, zero it. | 63 | } |
64 | TargetValue = Vector3.Zero; | 64 | } |
65 | CurrentValue = Vector3.Zero; | 65 | } |
66 | 66 | ||
67 | // VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); | 67 | // Motor which moves CurrentValue to TargetValue over TimeScale seconds. |
68 | } | 68 | // The TargetValue decays in TargetValueDecayTimeScale and |
69 | return CurrentValue; | 69 | // the CurrentValue will be held back by FrictionTimeScale. |
70 | } | 70 | // This motor will "zero itself" over time in that the targetValue will |
71 | } | 71 | // decay to zero and the currentValue will follow it to that zero. |
72 | 72 | // The overall effect is for the returned correction value to go from large | |
73 | public class BSFMotor : BSMotor | 73 | // values (the total difference between current and target minus friction) |
74 | { | 74 | // to small and eventually zero values. |
75 | public float TimeScale { get; set; } | 75 | // TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. |
76 | public float DecayTimeScale { get; set; } | 76 | |
77 | public float Friction { get; set; } | 77 | // For instance, if something is moving at speed X and the desired speed is Y, |
78 | public float Efficiency { get; set; } | 78 | // CurrentValue is X and TargetValue is Y. As the motor is stepped, new |
79 | 79 | // values of CurrentValue are returned that approach the TargetValue. | |
80 | public float Target { get; private set; } | 80 | // The feature of decaying TargetValue is so vehicles will eventually |
81 | public float CurrentValue { get; private set; } | 81 | // come to a stop rather than run forever. This can be disabled by |
82 | 82 | // setting TargetValueDecayTimescale to 'infinite'. | |
83 | BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency) | 83 | // The change from CurrentValue to TargetValue is linear over TimeScale seconds. |
84 | { | 84 | public class BSVMotor : BSMotor |
85 | } | 85 | { |
86 | public void SetCurrent(float target) | 86 | // public Vector3 FrameOfReference { get; set; } |
87 | { | 87 | // public Vector3 Offset { get; set; } |
88 | } | 88 | |
89 | public void SetTarget(float target) | 89 | public virtual float TimeScale { get; set; } |
90 | { | 90 | public virtual float TargetValueDecayTimeScale { get; set; } |
91 | } | 91 | public virtual Vector3 FrictionTimescale { get; set; } |
92 | public float Step(float timeStep) | 92 | public virtual float Efficiency { get; set; } |
93 | { | 93 | |
94 | return 0f; | 94 | public virtual float ErrorZeroThreshold { get; set; } |
95 | } | 95 | |
96 | } | 96 | public virtual Vector3 TargetValue { get; protected set; } |
97 | public class BSPIDMotor : BSMotor | 97 | public virtual Vector3 CurrentValue { get; protected set; } |
98 | { | 98 | public virtual Vector3 LastError { get; protected set; } |
99 | // TODO: write and use this one | 99 | |
100 | BSPIDMotor() | 100 | public virtual bool ErrorIsZero() |
101 | { | 101 | { |
102 | } | 102 | return ErrorIsZero(LastError); |
103 | } | 103 | } |
104 | } | 104 | public virtual bool ErrorIsZero(Vector3 err) |
105 | { | ||
106 | return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)); | ||
107 | } | ||
108 | |||
109 | public BSVMotor(string useName) | ||
110 | : base(useName) | ||
111 | { | ||
112 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; | ||
113 | Efficiency = 1f; | ||
114 | FrictionTimescale = BSMotor.InfiniteVector; | ||
115 | CurrentValue = TargetValue = Vector3.Zero; | ||
116 | ErrorZeroThreshold = 0.001f; | ||
117 | } | ||
118 | public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) | ||
119 | : this(useName) | ||
120 | { | ||
121 | TimeScale = timeScale; | ||
122 | TargetValueDecayTimeScale = decayTimeScale; | ||
123 | FrictionTimescale = frictionTimeScale; | ||
124 | Efficiency = efficiency; | ||
125 | CurrentValue = TargetValue = Vector3.Zero; | ||
126 | } | ||
127 | public void SetCurrent(Vector3 current) | ||
128 | { | ||
129 | CurrentValue = current; | ||
130 | } | ||
131 | public void SetTarget(Vector3 target) | ||
132 | { | ||
133 | TargetValue = target; | ||
134 | } | ||
135 | public override void Zero() | ||
136 | { | ||
137 | base.Zero(); | ||
138 | CurrentValue = TargetValue = Vector3.Zero; | ||
139 | } | ||
140 | |||
141 | // Compute the next step and return the new current value | ||
142 | public virtual Vector3 Step(float timeStep) | ||
143 | { | ||
144 | if (!Enabled) return TargetValue; | ||
145 | |||
146 | Vector3 origTarget = TargetValue; // DEBUG | ||
147 | Vector3 origCurrVal = CurrentValue; // DEBUG | ||
148 | |||
149 | Vector3 correction = Vector3.Zero; | ||
150 | Vector3 error = TargetValue - CurrentValue; | ||
151 | if (!ErrorIsZero(error)) | ||
152 | { | ||
153 | correction = Step(timeStep, error); | ||
154 | |||
155 | CurrentValue += correction; | ||
156 | |||
157 | // The desired value reduces to zero which also reduces the difference with current. | ||
158 | // If the decay time is infinite, don't decay at all. | ||
159 | float decayFactor = 0f; | ||
160 | if (TargetValueDecayTimeScale != BSMotor.Infinite) | ||
161 | { | ||
162 | decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | ||
163 | TargetValue *= (1f - decayFactor); | ||
164 | } | ||
165 | |||
166 | // The amount we can correct the error is reduced by the friction | ||
167 | Vector3 frictionFactor = Vector3.Zero; | ||
168 | if (FrictionTimescale != BSMotor.InfiniteVector) | ||
169 | { | ||
170 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
171 | // Individual friction components can be 'infinite' so compute each separately. | ||
172 | frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X); | ||
173 | frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y); | ||
174 | frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z); | ||
175 | frictionFactor *= timeStep; | ||
176 | CurrentValue *= (Vector3.One - frictionFactor); | ||
177 | } | ||
178 | |||
179 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", | ||
180 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | ||
181 | timeStep, error, correction); | ||
182 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", | ||
183 | BSScene.DetailLogZero, UseName, | ||
184 | TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor, | ||
185 | TargetValue, CurrentValue); | ||
186 | } | ||
187 | else | ||
188 | { | ||
189 | // Difference between what we have and target is small. Motor is done. | ||
190 | CurrentValue = TargetValue; | ||
191 | MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", | ||
192 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); | ||
193 | } | ||
194 | |||
195 | return CurrentValue; | ||
196 | } | ||
197 | public virtual Vector3 Step(float timeStep, Vector3 error) | ||
198 | { | ||
199 | if (!Enabled) return Vector3.Zero; | ||
200 | |||
201 | LastError = error; | ||
202 | Vector3 returnCorrection = Vector3.Zero; | ||
203 | if (!ErrorIsZero()) | ||
204 | { | ||
205 | // correction = error / secondsItShouldTakeToCorrect | ||
206 | Vector3 correctionAmount; | ||
207 | if (TimeScale == 0f || TimeScale == BSMotor.Infinite) | ||
208 | correctionAmount = error * timeStep; | ||
209 | else | ||
210 | correctionAmount = error / TimeScale * timeStep; | ||
211 | |||
212 | returnCorrection = correctionAmount; | ||
213 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", | ||
214 | BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); | ||
215 | } | ||
216 | return returnCorrection; | ||
217 | } | ||
218 | |||
219 | // The user sets all the parameters and calls this which outputs values until error is zero. | ||
220 | public override void GenerateTestOutput(float timeStep) | ||
221 | { | ||
222 | // maximum number of outputs to generate. | ||
223 | int maxOutput = 50; | ||
224 | MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); | ||
225 | MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}", | ||
226 | BSScene.DetailLogZero, UseName, | ||
227 | TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, | ||
228 | CurrentValue, TargetValue); | ||
229 | |||
230 | LastError = BSMotor.InfiniteVector; | ||
231 | while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) | ||
232 | { | ||
233 | Vector3 lastStep = Step(timeStep); | ||
234 | MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}", | ||
235 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); | ||
236 | } | ||
237 | MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); | ||
238 | |||
239 | |||
240 | } | ||
241 | |||
242 | public override string ToString() | ||
243 | { | ||
244 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", | ||
245 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | // ============================================================================ | ||
250 | // ============================================================================ | ||
251 | public class BSFMotor : BSMotor | ||
252 | { | ||
253 | public virtual float TimeScale { get; set; } | ||
254 | public virtual float TargetValueDecayTimeScale { get; set; } | ||
255 | public virtual float FrictionTimescale { get; set; } | ||
256 | public virtual float Efficiency { get; set; } | ||
257 | |||
258 | public virtual float ErrorZeroThreshold { get; set; } | ||
259 | |||
260 | public virtual float TargetValue { get; protected set; } | ||
261 | public virtual float CurrentValue { get; protected set; } | ||
262 | public virtual float LastError { get; protected set; } | ||
263 | |||
264 | public virtual bool ErrorIsZero() | ||
265 | { | ||
266 | return ErrorIsZero(LastError); | ||
267 | } | ||
268 | public virtual bool ErrorIsZero(float err) | ||
269 | { | ||
270 | return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); | ||
271 | } | ||
272 | |||
273 | public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) | ||
274 | : base(useName) | ||
275 | { | ||
276 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; | ||
277 | Efficiency = 1f; | ||
278 | FrictionTimescale = BSMotor.Infinite; | ||
279 | CurrentValue = TargetValue = 0f; | ||
280 | ErrorZeroThreshold = 0.01f; | ||
281 | } | ||
282 | public void SetCurrent(float current) | ||
283 | { | ||
284 | CurrentValue = current; | ||
285 | } | ||
286 | public void SetTarget(float target) | ||
287 | { | ||
288 | TargetValue = target; | ||
289 | } | ||
290 | public override void Zero() | ||
291 | { | ||
292 | base.Zero(); | ||
293 | CurrentValue = TargetValue = 0f; | ||
294 | } | ||
295 | |||
296 | public virtual float Step(float timeStep) | ||
297 | { | ||
298 | if (!Enabled) return TargetValue; | ||
299 | |||
300 | float origTarget = TargetValue; // DEBUG | ||
301 | float origCurrVal = CurrentValue; // DEBUG | ||
302 | |||
303 | float correction = 0f; | ||
304 | float error = TargetValue - CurrentValue; | ||
305 | if (!ErrorIsZero(error)) | ||
306 | { | ||
307 | correction = Step(timeStep, error); | ||
308 | |||
309 | CurrentValue += correction; | ||
310 | |||
311 | // The desired value reduces to zero which also reduces the difference with current. | ||
312 | // If the decay time is infinite, don't decay at all. | ||
313 | float decayFactor = 0f; | ||
314 | if (TargetValueDecayTimeScale != BSMotor.Infinite) | ||
315 | { | ||
316 | decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | ||
317 | TargetValue *= (1f - decayFactor); | ||
318 | } | ||
319 | |||
320 | // The amount we can correct the error is reduced by the friction | ||
321 | float frictionFactor = 0f; | ||
322 | if (FrictionTimescale != BSMotor.Infinite) | ||
323 | { | ||
324 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
325 | // Individual friction components can be 'infinite' so compute each separately. | ||
326 | frictionFactor = 1f / FrictionTimescale; | ||
327 | frictionFactor *= timeStep; | ||
328 | CurrentValue *= (1f - frictionFactor); | ||
329 | } | ||
330 | |||
331 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", | ||
332 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | ||
333 | timeStep, error, correction); | ||
334 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", | ||
335 | BSScene.DetailLogZero, UseName, | ||
336 | TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor, | ||
337 | TargetValue, CurrentValue); | ||
338 | } | ||
339 | else | ||
340 | { | ||
341 | // Difference between what we have and target is small. Motor is done. | ||
342 | CurrentValue = TargetValue; | ||
343 | MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", | ||
344 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); | ||
345 | } | ||
346 | |||
347 | return CurrentValue; | ||
348 | } | ||
349 | |||
350 | public virtual float Step(float timeStep, float error) | ||
351 | { | ||
352 | if (!Enabled) return 0f; | ||
353 | |||
354 | LastError = error; | ||
355 | float returnCorrection = 0f; | ||
356 | if (!ErrorIsZero()) | ||
357 | { | ||
358 | // correction = error / secondsItShouldTakeToCorrect | ||
359 | float correctionAmount; | ||
360 | if (TimeScale == 0f || TimeScale == BSMotor.Infinite) | ||
361 | correctionAmount = error * timeStep; | ||
362 | else | ||
363 | correctionAmount = error / TimeScale * timeStep; | ||
364 | |||
365 | returnCorrection = correctionAmount; | ||
366 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", | ||
367 | BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); | ||
368 | } | ||
369 | return returnCorrection; | ||
370 | } | ||
371 | |||
372 | public override string ToString() | ||
373 | { | ||
374 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", | ||
375 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); | ||
376 | } | ||
377 | |||
378 | } | ||
379 | |||
380 | // ============================================================================ | ||
381 | // ============================================================================ | ||
382 | // Proportional, Integral, Derivitive Motor | ||
383 | // Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. | ||
384 | public class BSPIDVMotor : BSVMotor | ||
385 | { | ||
386 | // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10. | ||
387 | public Vector3 proportionFactor { get; set; } | ||
388 | public Vector3 integralFactor { get; set; } | ||
389 | public Vector3 derivFactor { get; set; } | ||
390 | |||
391 | // The factors are vectors for the three dimensions. This is the proportional of each | ||
392 | // that is applied. This could be multiplied through the actual factors but it | ||
393 | // is sometimes easier to manipulate the factors and their mix separately. | ||
394 | // to | ||
395 | public Vector3 FactorMix; | ||
396 | |||
397 | // Arbritrary factor range. | ||
398 | // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. | ||
399 | public float EfficiencyHigh = 0.4f; | ||
400 | public float EfficiencyLow = 4.0f; | ||
401 | |||
402 | // Running integration of the error | ||
403 | Vector3 RunningIntegration { get; set; } | ||
404 | |||
405 | public BSPIDVMotor(string useName) | ||
406 | : base(useName) | ||
407 | { | ||
408 | proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||
409 | integralFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||
410 | derivFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||
411 | FactorMix = new Vector3(0.5f, 0.25f, 0.25f); | ||
412 | RunningIntegration = Vector3.Zero; | ||
413 | LastError = Vector3.Zero; | ||
414 | } | ||
415 | |||
416 | public override void Zero() | ||
417 | { | ||
418 | base.Zero(); | ||
419 | } | ||
420 | |||
421 | public override float Efficiency | ||
422 | { | ||
423 | get { return base.Efficiency; } | ||
424 | set | ||
425 | { | ||
426 | base.Efficiency = Util.Clamp(value, 0f, 1f); | ||
427 | |||
428 | // Compute factors based on efficiency. | ||
429 | // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot. | ||
430 | // If efficiency is low (0f), use a factor value that overcorrects. | ||
431 | // TODO: might want to vary contribution of different factor depending on efficiency. | ||
432 | float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; | ||
433 | // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; | ||
434 | |||
435 | proportionFactor = new Vector3(factor, factor, factor); | ||
436 | integralFactor = new Vector3(factor, factor, factor); | ||
437 | derivFactor = new Vector3(factor, factor, factor); | ||
438 | |||
439 | MDetailLog("{0},BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor); | ||
440 | } | ||
441 | } | ||
442 | |||
443 | // Ignore Current and Target Values and just advance the PID computation on this error. | ||
444 | public override Vector3 Step(float timeStep, Vector3 error) | ||
445 | { | ||
446 | if (!Enabled) return Vector3.Zero; | ||
447 | |||
448 | // Add up the error so we can integrate over the accumulated errors | ||
449 | RunningIntegration += error * timeStep; | ||
450 | |||
451 | // A simple derivitive is the rate of change from the last error. | ||
452 | Vector3 derivitive = (error - LastError) * timeStep; | ||
453 | LastError = error; | ||
454 | |||
455 | // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) | ||
456 | Vector3 ret = error * timeStep * proportionFactor * FactorMix.X | ||
457 | + RunningIntegration * integralFactor * FactorMix.Y | ||
458 | + derivitive * derivFactor * FactorMix.Z | ||
459 | ; | ||
460 | |||
461 | MDetailLog("{0},BSPIDVMotor.step,ts={1},err={2},runnInt={3},deriv={4},ret={5}", | ||
462 | BSScene.DetailLogZero, timeStep, error, RunningIntegration, derivitive, ret); | ||
463 | |||
464 | return ret; | ||
465 | } | ||
466 | } | ||
467 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs new file mode 100755 index 0000000..b9bd0bf --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | |||
@@ -0,0 +1,610 @@ | |||
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.Physics.Manager; | ||
32 | |||
33 | using OpenMetaverse; | ||
34 | using Nini.Config; | ||
35 | |||
36 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
37 | { | ||
38 | public static class BSParam | ||
39 | { | ||
40 | // Level of Detail values kept as float because that's what the Meshmerizer wants | ||
41 | public static float MeshLOD { get; private set; } | ||
42 | public static float MeshMegaPrimLOD { get; private set; } | ||
43 | public static float MeshMegaPrimThreshold { get; private set; } | ||
44 | public static float SculptLOD { get; private set; } | ||
45 | |||
46 | public static float MinimumObjectMass { get; private set; } | ||
47 | public static float MaximumObjectMass { get; private set; } | ||
48 | |||
49 | public static float LinearDamping { get; private set; } | ||
50 | public static float AngularDamping { get; private set; } | ||
51 | public static float DeactivationTime { get; private set; } | ||
52 | public static float LinearSleepingThreshold { get; private set; } | ||
53 | public static float AngularSleepingThreshold { get; private set; } | ||
54 | public static float CcdMotionThreshold { get; private set; } | ||
55 | public static float CcdSweptSphereRadius { get; private set; } | ||
56 | public static float ContactProcessingThreshold { get; private set; } | ||
57 | |||
58 | public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed | ||
59 | public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes | ||
60 | public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects | ||
61 | |||
62 | public static float TerrainImplementation { get; private set; } | ||
63 | public static float TerrainFriction { get; private set; } | ||
64 | public static float TerrainHitFraction { get; private set; } | ||
65 | public static float TerrainRestitution { get; private set; } | ||
66 | public static float TerrainCollisionMargin { get; private set; } | ||
67 | |||
68 | // Avatar parameters | ||
69 | public static float AvatarFriction { get; private set; } | ||
70 | public static float AvatarStandingFriction { get; private set; } | ||
71 | public static float AvatarAlwaysRunFactor { get; private set; } | ||
72 | public static float AvatarDensity { get; private set; } | ||
73 | public static float AvatarRestitution { get; private set; } | ||
74 | public static float AvatarCapsuleWidth { get; private set; } | ||
75 | public static float AvatarCapsuleDepth { get; private set; } | ||
76 | public static float AvatarCapsuleHeight { get; private set; } | ||
77 | public static float AvatarContactProcessingThreshold { get; private set; } | ||
78 | |||
79 | public static float VehicleAngularDamping { get; private set; } | ||
80 | |||
81 | public static float LinksetImplementation { get; private set; } | ||
82 | public static float LinkConstraintUseFrameOffset { get; private set; } | ||
83 | public static float LinkConstraintEnableTransMotor { get; private set; } | ||
84 | public static float LinkConstraintTransMotorMaxVel { get; private set; } | ||
85 | public static float LinkConstraintTransMotorMaxForce { get; private set; } | ||
86 | public static float LinkConstraintERP { get; private set; } | ||
87 | public static float LinkConstraintCFM { get; private set; } | ||
88 | public static float LinkConstraintSolverIterations { get; private set; } | ||
89 | |||
90 | public static float PID_D { get; private set; } // derivative | ||
91 | public static float PID_P { get; private set; } // proportional | ||
92 | |||
93 | // Various constants that come from that other virtual world that shall not be named | ||
94 | public const float MinGravityZ = -1f; | ||
95 | public const float MaxGravityZ = 28f; | ||
96 | public const float MinFriction = 0f; | ||
97 | public const float MaxFriction = 255f; | ||
98 | public const float MinDensity = 0f; | ||
99 | public const float MaxDensity = 22587f; | ||
100 | public const float MinRestitution = 0f; | ||
101 | public const float MaxRestitution = 1f; | ||
102 | public const float MaxAddForceMagnitude = 20000f; | ||
103 | |||
104 | // =========================================================================== | ||
105 | public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); | ||
106 | public delegate float ParamGet(BSScene scene); | ||
107 | public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); | ||
108 | public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val); | ||
109 | |||
110 | public struct ParameterDefn | ||
111 | { | ||
112 | public string name; // string name of the parameter | ||
113 | public string desc; // a short description of what the parameter means | ||
114 | public float defaultValue; // default value if not specified anywhere else | ||
115 | public ParamUser userParam; // get the value from the configuration file | ||
116 | public ParamGet getter; // return the current value stored for this parameter | ||
117 | public ParamSet setter; // set the current value for this parameter | ||
118 | public SetOnObject onObject; // set the value on an object in the physical domain | ||
119 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) | ||
120 | { | ||
121 | name = n; | ||
122 | desc = d; | ||
123 | defaultValue = v; | ||
124 | userParam = u; | ||
125 | getter = g; | ||
126 | setter = s; | ||
127 | onObject = null; | ||
128 | } | ||
129 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o) | ||
130 | { | ||
131 | name = n; | ||
132 | desc = d; | ||
133 | defaultValue = v; | ||
134 | userParam = u; | ||
135 | getter = g; | ||
136 | setter = s; | ||
137 | onObject = o; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | // List of all of the externally visible parameters. | ||
142 | // For each parameter, this table maps a text name to getter and setters. | ||
143 | // To add a new externally referencable/settable parameter, add the paramter storage | ||
144 | // location somewhere in the program and make an entry in this table with the | ||
145 | // getters and setters. | ||
146 | // It is easiest to find an existing definition and copy it. | ||
147 | // Parameter values are floats. Booleans are converted to a floating value. | ||
148 | // | ||
149 | // A ParameterDefn() takes the following parameters: | ||
150 | // -- the text name of the parameter. This is used for console input and ini file. | ||
151 | // -- a short text description of the parameter. This shows up in the console listing. | ||
152 | // -- a default value (float) | ||
153 | // -- a delegate for fetching the parameter from the ini file. | ||
154 | // Should handle fetching the right type from the ini file and converting it. | ||
155 | // -- a delegate for getting the value as a float | ||
156 | // -- a delegate for setting the value from a float | ||
157 | // -- an optional delegate to update the value in the world. Most often used to | ||
158 | // push the new value to an in-world object. | ||
159 | // | ||
160 | // The single letter parameters for the delegates are: | ||
161 | // s = BSScene | ||
162 | // o = BSPhysObject | ||
163 | // p = string parameter name | ||
164 | // l = localID of referenced object | ||
165 | // v = value (float) | ||
166 | // cf = parameter configuration class (for fetching values from ini file) | ||
167 | private static ParameterDefn[] ParameterDefinitions = | ||
168 | { | ||
169 | new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", | ||
170 | ConfigurationParameters.numericTrue, | ||
171 | (s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, | ||
172 | (s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); }, | ||
173 | (s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ), | ||
174 | new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", | ||
175 | ConfigurationParameters.numericFalse, | ||
176 | (s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, | ||
177 | (s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); }, | ||
178 | (s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ), | ||
179 | new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", | ||
180 | ConfigurationParameters.numericTrue, | ||
181 | (s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, | ||
182 | (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); }, | ||
183 | (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ), | ||
184 | |||
185 | new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | ||
186 | 8f, | ||
187 | (s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); }, | ||
188 | (s) => { return MeshLOD; }, | ||
189 | (s,p,l,v) => { MeshLOD = v; } ), | ||
190 | new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", | ||
191 | 16f, | ||
192 | (s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); }, | ||
193 | (s) => { return MeshMegaPrimLOD; }, | ||
194 | (s,p,l,v) => { MeshMegaPrimLOD = v; } ), | ||
195 | new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", | ||
196 | 10f, | ||
197 | (s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); }, | ||
198 | (s) => { return MeshMegaPrimThreshold; }, | ||
199 | (s,p,l,v) => { MeshMegaPrimThreshold = v; } ), | ||
200 | new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", | ||
201 | 32f, | ||
202 | (s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); }, | ||
203 | (s) => { return SculptLOD; }, | ||
204 | (s,p,l,v) => { SculptLOD = v; } ), | ||
205 | |||
206 | new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", | ||
207 | 10f, | ||
208 | (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); }, | ||
209 | (s) => { return (float)s.m_maxSubSteps; }, | ||
210 | (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ), | ||
211 | new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", | ||
212 | 1f / 60f, | ||
213 | (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); }, | ||
214 | (s) => { return (float)s.m_fixedTimeStep; }, | ||
215 | (s,p,l,v) => { s.m_fixedTimeStep = v; } ), | ||
216 | new ParameterDefn("NominalFrameRate", "The base frame rate we claim", | ||
217 | 55f, | ||
218 | (s,cf,p,v) => { s.NominalFrameRate = cf.GetInt(p, (int)v); }, | ||
219 | (s) => { return (float)s.NominalFrameRate; }, | ||
220 | (s,p,l,v) => { s.NominalFrameRate = (int)v; } ), | ||
221 | new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", | ||
222 | 2048f, | ||
223 | (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); }, | ||
224 | (s) => { return (float)s.m_maxCollisionsPerFrame; }, | ||
225 | (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), | ||
226 | new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame", | ||
227 | 8000f, | ||
228 | (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, | ||
229 | (s) => { return (float)s.m_maxUpdatesPerFrame; }, | ||
230 | (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), | ||
231 | new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", | ||
232 | 500f, | ||
233 | (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, | ||
234 | (s) => { return (float)s.m_taintsToProcessPerStep; }, | ||
235 | (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), | ||
236 | new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)", | ||
237 | 0.0001f, | ||
238 | (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); }, | ||
239 | (s) => { return (float)MinimumObjectMass; }, | ||
240 | (s,p,l,v) => { MinimumObjectMass = v; } ), | ||
241 | new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", | ||
242 | 10000.01f, | ||
243 | (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); }, | ||
244 | (s) => { return (float)MaximumObjectMass; }, | ||
245 | (s,p,l,v) => { MaximumObjectMass = v; } ), | ||
246 | |||
247 | new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", | ||
248 | 2200f, | ||
249 | (s,cf,p,v) => { PID_D = cf.GetFloat(p, v); }, | ||
250 | (s) => { return (float)PID_D; }, | ||
251 | (s,p,l,v) => { PID_D = v; } ), | ||
252 | new ParameterDefn("PID_P", "Parameteric factor for motion smoothing", | ||
253 | 900f, | ||
254 | (s,cf,p,v) => { PID_P = cf.GetFloat(p, v); }, | ||
255 | (s) => { return (float)PID_P; }, | ||
256 | (s,p,l,v) => { PID_P = v; } ), | ||
257 | |||
258 | new ParameterDefn("DefaultFriction", "Friction factor used on new objects", | ||
259 | 0.2f, | ||
260 | (s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); }, | ||
261 | (s) => { return s.UnmanagedParams[0].defaultFriction; }, | ||
262 | (s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ), | ||
263 | new ParameterDefn("DefaultDensity", "Density for new objects" , | ||
264 | 10.000006836f, // Aluminum g/cm3 | ||
265 | (s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); }, | ||
266 | (s) => { return s.UnmanagedParams[0].defaultDensity; }, | ||
267 | (s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ), | ||
268 | new ParameterDefn("DefaultRestitution", "Bouncyness of an object" , | ||
269 | 0f, | ||
270 | (s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); }, | ||
271 | (s) => { return s.UnmanagedParams[0].defaultRestitution; }, | ||
272 | (s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ), | ||
273 | new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", | ||
274 | 0.04f, | ||
275 | (s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); }, | ||
276 | (s) => { return s.UnmanagedParams[0].collisionMargin; }, | ||
277 | (s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ), | ||
278 | new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)", | ||
279 | -9.80665f, | ||
280 | (s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); }, | ||
281 | (s) => { return s.UnmanagedParams[0].gravity; }, | ||
282 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); }, | ||
283 | (s,o,v) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,v)); } ), | ||
284 | |||
285 | |||
286 | new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", | ||
287 | 0f, | ||
288 | (s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); }, | ||
289 | (s) => { return LinearDamping; }, | ||
290 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); }, | ||
291 | (s,o,v) => { s.PE.SetDamping(o.PhysBody, v, AngularDamping); } ), | ||
292 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", | ||
293 | 0f, | ||
294 | (s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); }, | ||
295 | (s) => { return AngularDamping; }, | ||
296 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); }, | ||
297 | (s,o,v) => { s.PE.SetDamping(o.PhysBody, LinearDamping, v); } ), | ||
298 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", | ||
299 | 0.2f, | ||
300 | (s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); }, | ||
301 | (s) => { return DeactivationTime; }, | ||
302 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); }, | ||
303 | (s,o,v) => { s.PE.SetDeactivationTime(o.PhysBody, v); } ), | ||
304 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", | ||
305 | 0.8f, | ||
306 | (s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); }, | ||
307 | (s) => { return LinearSleepingThreshold; }, | ||
308 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); }, | ||
309 | (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ), | ||
310 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", | ||
311 | 1.0f, | ||
312 | (s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); }, | ||
313 | (s) => { return AngularSleepingThreshold; }, | ||
314 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); }, | ||
315 | (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ), | ||
316 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , | ||
317 | 0f, // set to zero to disable | ||
318 | (s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); }, | ||
319 | (s) => { return CcdMotionThreshold; }, | ||
320 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); }, | ||
321 | (s,o,v) => { s.PE.SetCcdMotionThreshold(o.PhysBody, v); } ), | ||
322 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , | ||
323 | 0f, | ||
324 | (s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); }, | ||
325 | (s) => { return CcdSweptSphereRadius; }, | ||
326 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); }, | ||
327 | (s,o,v) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, v); } ), | ||
328 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , | ||
329 | 0.1f, | ||
330 | (s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); }, | ||
331 | (s) => { return ContactProcessingThreshold; }, | ||
332 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); }, | ||
333 | (s,o,v) => { s.PE.SetContactProcessingThreshold(o.PhysBody, v); } ), | ||
334 | |||
335 | new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", | ||
336 | (float)BSTerrainPhys.TerrainImplementation.Mesh, | ||
337 | (s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); }, | ||
338 | (s) => { return TerrainImplementation; }, | ||
339 | (s,p,l,v) => { TerrainImplementation = v; } ), | ||
340 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | ||
341 | 0.3f, | ||
342 | (s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); }, | ||
343 | (s) => { return TerrainFriction; }, | ||
344 | (s,p,l,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ), | ||
345 | new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , | ||
346 | 0.8f, | ||
347 | (s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); }, | ||
348 | (s) => { return TerrainHitFraction; }, | ||
349 | (s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ), | ||
350 | new ParameterDefn("TerrainRestitution", "Bouncyness" , | ||
351 | 0f, | ||
352 | (s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); }, | ||
353 | (s) => { return TerrainRestitution; }, | ||
354 | (s,p,l,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ), | ||
355 | new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , | ||
356 | 0.04f, | ||
357 | (s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); }, | ||
358 | (s) => { return TerrainCollisionMargin; }, | ||
359 | (s,p,l,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ), | ||
360 | |||
361 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | ||
362 | 0.2f, | ||
363 | (s,cf,p,v) => { AvatarFriction = cf.GetFloat(p, v); }, | ||
364 | (s) => { return AvatarFriction; }, | ||
365 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ), | ||
366 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | ||
367 | 10.0f, | ||
368 | (s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); }, | ||
369 | (s) => { return AvatarStandingFriction; }, | ||
370 | (s,p,l,v) => { AvatarStandingFriction = v; } ), | ||
371 | new ParameterDefn("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", | ||
372 | 1.3f, | ||
373 | (s,cf,p,v) => { AvatarAlwaysRunFactor = cf.GetFloat(p, v); }, | ||
374 | (s) => { return AvatarAlwaysRunFactor; }, | ||
375 | (s,p,l,v) => { AvatarAlwaysRunFactor = v; } ), | ||
376 | new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | ||
377 | 3.5f, | ||
378 | (s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); }, | ||
379 | (s) => { return AvatarDensity; }, | ||
380 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ), | ||
381 | new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", | ||
382 | 0f, | ||
383 | (s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); }, | ||
384 | (s) => { return AvatarRestitution; }, | ||
385 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ), | ||
386 | new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", | ||
387 | 0.6f, | ||
388 | (s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); }, | ||
389 | (s) => { return AvatarCapsuleWidth; }, | ||
390 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ), | ||
391 | new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", | ||
392 | 0.45f, | ||
393 | (s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); }, | ||
394 | (s) => { return AvatarCapsuleDepth; }, | ||
395 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ), | ||
396 | new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", | ||
397 | 1.5f, | ||
398 | (s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); }, | ||
399 | (s) => { return AvatarCapsuleHeight; }, | ||
400 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ), | ||
401 | new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | ||
402 | 0.1f, | ||
403 | (s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); }, | ||
404 | (s) => { return AvatarContactProcessingThreshold; }, | ||
405 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ), | ||
406 | |||
407 | new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", | ||
408 | 0.95f, | ||
409 | (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); }, | ||
410 | (s) => { return VehicleAngularDamping; }, | ||
411 | (s,p,l,v) => { VehicleAngularDamping = v; } ), | ||
412 | |||
413 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | ||
414 | 0f, | ||
415 | (s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, | ||
416 | (s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; }, | ||
417 | (s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ), | ||
418 | new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", | ||
419 | 0f, | ||
420 | (s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, | ||
421 | (s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; }, | ||
422 | (s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ), | ||
423 | new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", | ||
424 | ConfigurationParameters.numericFalse, | ||
425 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
426 | (s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; }, | ||
427 | (s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ), | ||
428 | new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", | ||
429 | ConfigurationParameters.numericFalse, | ||
430 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
431 | (s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; }, | ||
432 | (s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ), | ||
433 | new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", | ||
434 | ConfigurationParameters.numericTrue, | ||
435 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
436 | (s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; }, | ||
437 | (s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ), | ||
438 | new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", | ||
439 | ConfigurationParameters.numericTrue, | ||
440 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
441 | (s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; }, | ||
442 | (s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ), | ||
443 | new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching", | ||
444 | ConfigurationParameters.numericFalse, | ||
445 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
446 | (s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; }, | ||
447 | (s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ), | ||
448 | new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)", | ||
449 | 0f, // zero says use Bullet default | ||
450 | (s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); }, | ||
451 | (s) => { return s.UnmanagedParams[0].numberOfSolverIterations; }, | ||
452 | (s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ), | ||
453 | |||
454 | new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | ||
455 | (float)BSLinkset.LinksetImplementation.Compound, | ||
456 | (s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); }, | ||
457 | (s) => { return LinksetImplementation; }, | ||
458 | (s,p,l,v) => { LinksetImplementation = v; } ), | ||
459 | new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | ||
460 | ConfigurationParameters.numericFalse, | ||
461 | (s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
462 | (s) => { return LinkConstraintUseFrameOffset; }, | ||
463 | (s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ), | ||
464 | new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", | ||
465 | ConfigurationParameters.numericTrue, | ||
466 | (s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
467 | (s) => { return LinkConstraintEnableTransMotor; }, | ||
468 | (s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ), | ||
469 | new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", | ||
470 | 5.0f, | ||
471 | (s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); }, | ||
472 | (s) => { return LinkConstraintTransMotorMaxVel; }, | ||
473 | (s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ), | ||
474 | new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", | ||
475 | 0.1f, | ||
476 | (s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, | ||
477 | (s) => { return LinkConstraintTransMotorMaxForce; }, | ||
478 | (s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ), | ||
479 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | ||
480 | 0.1f, | ||
481 | (s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); }, | ||
482 | (s) => { return LinkConstraintCFM; }, | ||
483 | (s,p,l,v) => { LinkConstraintCFM = v; } ), | ||
484 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | ||
485 | 0.1f, | ||
486 | (s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); }, | ||
487 | (s) => { return LinkConstraintERP; }, | ||
488 | (s,p,l,v) => { LinkConstraintERP = v; } ), | ||
489 | new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", | ||
490 | 40, | ||
491 | (s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); }, | ||
492 | (s) => { return LinkConstraintSolverIterations; }, | ||
493 | (s,p,l,v) => { LinkConstraintSolverIterations = v; } ), | ||
494 | |||
495 | new ParameterDefn("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", | ||
496 | 0f, | ||
497 | (s,cf,p,v) => { s.PhysicsMetricDumpFrames = cf.GetFloat(p, (int)v); }, | ||
498 | (s) => { return (float)s.PhysicsMetricDumpFrames; }, | ||
499 | (s,p,l,v) => { s.PhysicsMetricDumpFrames = (int)v; } ), | ||
500 | new ParameterDefn("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool", | ||
501 | 0f, | ||
502 | (s,cf,p,v) => { ; }, | ||
503 | (s) => { return 0f; }, | ||
504 | (s,p,l,v) => { BSParam.ResetBroadphasePoolTainted(s, v); } ), | ||
505 | new ParameterDefn("ResetConstraintSolver", "Setting this is any value resets the constraint solver", | ||
506 | 0f, | ||
507 | (s,cf,p,v) => { ; }, | ||
508 | (s) => { return 0f; }, | ||
509 | (s,p,l,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ), | ||
510 | }; | ||
511 | |||
512 | // Convert a boolean to our numeric true and false values | ||
513 | public static float NumericBool(bool b) | ||
514 | { | ||
515 | return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse); | ||
516 | } | ||
517 | |||
518 | // Convert numeric true and false values to a boolean | ||
519 | public static bool BoolNumeric(float b) | ||
520 | { | ||
521 | return (b == ConfigurationParameters.numericTrue ? true : false); | ||
522 | } | ||
523 | |||
524 | private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v) | ||
525 | { | ||
526 | BSScene physScene = pPhysScene; | ||
527 | physScene.TaintedObject("BSParam.ResetBroadphasePoolTainted", delegate() | ||
528 | { | ||
529 | physScene.PE.ResetBroadphasePool(physScene.World); | ||
530 | }); | ||
531 | } | ||
532 | |||
533 | private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v) | ||
534 | { | ||
535 | BSScene physScene = pPhysScene; | ||
536 | physScene.TaintedObject("BSParam.ResetConstraintSolver", delegate() | ||
537 | { | ||
538 | physScene.PE.ResetConstraintSolver(physScene.World); | ||
539 | }); | ||
540 | } | ||
541 | |||
542 | // Search through the parameter definitions and return the matching | ||
543 | // ParameterDefn structure. | ||
544 | // Case does not matter as names are compared after converting to lower case. | ||
545 | // Returns 'false' if the parameter is not found. | ||
546 | internal static bool TryGetParameter(string paramName, out ParameterDefn defn) | ||
547 | { | ||
548 | bool ret = false; | ||
549 | ParameterDefn foundDefn = new ParameterDefn(); | ||
550 | string pName = paramName.ToLower(); | ||
551 | |||
552 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
553 | { | ||
554 | if (pName == parm.name.ToLower()) | ||
555 | { | ||
556 | foundDefn = parm; | ||
557 | ret = true; | ||
558 | break; | ||
559 | } | ||
560 | } | ||
561 | defn = foundDefn; | ||
562 | return ret; | ||
563 | } | ||
564 | |||
565 | // Pass through the settable parameters and set the default values | ||
566 | internal static void SetParameterDefaultValues(BSScene physicsScene) | ||
567 | { | ||
568 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
569 | { | ||
570 | parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue); | ||
571 | } | ||
572 | } | ||
573 | |||
574 | // Get user set values out of the ini file. | ||
575 | internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg) | ||
576 | { | ||
577 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
578 | { | ||
579 | parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue); | ||
580 | } | ||
581 | } | ||
582 | |||
583 | internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; | ||
584 | |||
585 | // This creates an array in the correct format for returning the list of | ||
586 | // parameters. This is used by the 'list' option of the 'physics' command. | ||
587 | internal static void BuildParameterTable() | ||
588 | { | ||
589 | if (SettableParameters.Length < ParameterDefinitions.Length) | ||
590 | { | ||
591 | List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); | ||
592 | for (int ii = 0; ii < ParameterDefinitions.Length; ii++) | ||
593 | { | ||
594 | ParameterDefn pd = ParameterDefinitions[ii]; | ||
595 | entries.Add(new PhysParameterEntry(pd.name, pd.desc)); | ||
596 | } | ||
597 | |||
598 | // make the list in alphabetical order for estetic reasons | ||
599 | entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2) | ||
600 | { | ||
601 | return ppe1.name.CompareTo(ppe2.name); | ||
602 | }); | ||
603 | |||
604 | SettableParameters = entries.ToArray(); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | |||
609 | } | ||
610 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index f6a890e..534f929 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | |||
@@ -45,6 +45,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
45 | * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. | 45 | * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. |
46 | * The last two (and certainly the last one) should be referenced only in taint-time. | 46 | * The last two (and certainly the last one) should be referenced only in taint-time. |
47 | */ | 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 | |||
48 | public abstract class BSPhysObject : PhysicsActor | 58 | public abstract class BSPhysObject : PhysicsActor |
49 | { | 59 | { |
50 | protected BSPhysObject() | 60 | protected BSPhysObject() |
@@ -57,26 +67,42 @@ public abstract class BSPhysObject : PhysicsActor | |||
57 | PhysObjectName = name; | 67 | PhysObjectName = name; |
58 | TypeName = typeName; | 68 | TypeName = typeName; |
59 | 69 | ||
70 | // We don't have any physical representation yet. | ||
71 | PhysBody = new BulletBody(localID); | ||
72 | PhysShape = new BulletShape(); | ||
73 | |||
74 | // A linkset of just me | ||
60 | Linkset = BSLinkset.Factory(PhysicsScene, this); | 75 | Linkset = BSLinkset.Factory(PhysicsScene, this); |
61 | LastAssetBuildFailed = false; | 76 | LastAssetBuildFailed = false; |
62 | 77 | ||
78 | // Default material type | ||
79 | Material = MaterialAttributes.Material.Wood; | ||
80 | |||
63 | CollisionCollection = new CollisionEventUpdate(); | 81 | CollisionCollection = new CollisionEventUpdate(); |
64 | SubscribedEventsMs = 0; | 82 | SubscribedEventsMs = 0; |
65 | CollidingStep = 0; | 83 | CollidingStep = 0; |
66 | CollidingGroundStep = 0; | 84 | CollidingGroundStep = 0; |
67 | } | 85 | } |
68 | 86 | ||
87 | // Tell the object to clean up. | ||
88 | public virtual void Destroy() | ||
89 | { | ||
90 | UnRegisterAllPreStepActions(); | ||
91 | } | ||
92 | |||
69 | public BSScene PhysicsScene { get; protected set; } | 93 | public BSScene PhysicsScene { get; protected set; } |
70 | // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor | 94 | // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor |
71 | public string PhysObjectName { get; protected set; } | 95 | public string PhysObjectName { get; protected set; } |
72 | public string TypeName { get; protected set; } | 96 | public string TypeName { get; protected set; } |
73 | 97 | ||
74 | public BSLinkset Linkset { get; set; } | 98 | public BSLinkset Linkset { get; set; } |
99 | public BSLinksetInfo LinksetInfo { get; set; } | ||
75 | 100 | ||
76 | // Return the object mass without calculating it or having side effects | 101 | // Return the object mass without calculating it or having side effects |
77 | public abstract float RawMass { get; } | 102 | public abstract float RawMass { get; } |
78 | // Set the raw mass but also update physical mass properties (inertia, ...) | 103 | // Set the raw mass but also update physical mass properties (inertia, ...) |
79 | public abstract void UpdatePhysicalMassProperties(float mass); | 104 | // 'inWorld' true if the object has already been added to the dynamic world. |
105 | public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld); | ||
80 | 106 | ||
81 | // The last value calculated for the prim's inertia | 107 | // The last value calculated for the prim's inertia |
82 | public OMV.Vector3 Inertia { get; set; } | 108 | public OMV.Vector3 Inertia { get; set; } |
@@ -105,10 +131,17 @@ public abstract class BSPhysObject : PhysicsActor | |||
105 | public EntityProperties CurrentEntityProperties { get; set; } | 131 | public EntityProperties CurrentEntityProperties { get; set; } |
106 | public EntityProperties LastEntityProperties { get; set; } | 132 | public EntityProperties LastEntityProperties { get; set; } |
107 | 133 | ||
108 | public abstract OMV.Vector3 Scale { get; set; } | 134 | public virtual OMV.Vector3 Scale { get; set; } |
109 | public abstract bool IsSolid { get; } | 135 | public abstract bool IsSolid { get; } |
110 | public abstract bool IsStatic { get; } | 136 | public abstract bool IsStatic { get; } |
111 | 137 | ||
138 | // Materialness | ||
139 | public MaterialAttributes.Material Material { get; private set; } | ||
140 | public override void SetMaterial(int material) | ||
141 | { | ||
142 | Material = (MaterialAttributes.Material)material; | ||
143 | } | ||
144 | |||
112 | // Stop all physical motion. | 145 | // Stop all physical motion. |
113 | public abstract void ZeroMotion(bool inTaintTime); | 146 | public abstract void ZeroMotion(bool inTaintTime); |
114 | public abstract void ZeroAngularMotion(bool inTaintTime); | 147 | public abstract void ZeroAngularMotion(bool inTaintTime); |
@@ -119,15 +152,23 @@ public abstract class BSPhysObject : PhysicsActor | |||
119 | // Update the physical location and motion of the object. Called with data from Bullet. | 152 | // Update the physical location and motion of the object. Called with data from Bullet. |
120 | public abstract void UpdateProperties(EntityProperties entprop); | 153 | public abstract void UpdateProperties(EntityProperties entprop); |
121 | 154 | ||
122 | // Tell the object to clean up. | ||
123 | public abstract void Destroy(); | ||
124 | |||
125 | public abstract OMV.Vector3 RawPosition { get; set; } | 155 | public abstract OMV.Vector3 RawPosition { get; set; } |
126 | public abstract OMV.Vector3 ForcePosition { get; set; } | 156 | public abstract OMV.Vector3 ForcePosition { get; set; } |
127 | 157 | ||
128 | public abstract OMV.Quaternion RawOrientation { get; set; } | 158 | public abstract OMV.Quaternion RawOrientation { get; set; } |
129 | public abstract OMV.Quaternion ForceOrientation { get; set; } | 159 | public abstract OMV.Quaternion ForceOrientation { get; set; } |
130 | 160 | ||
161 | // The system is telling us the velocity it wants to move at. | ||
162 | // protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor | ||
163 | public override OMV.Vector3 TargetVelocity | ||
164 | { | ||
165 | get { return m_targetVelocity; } | ||
166 | set | ||
167 | { | ||
168 | m_targetVelocity = value; | ||
169 | Velocity = value; | ||
170 | } | ||
171 | } | ||
131 | public abstract OMV.Vector3 ForceVelocity { get; set; } | 172 | public abstract OMV.Vector3 ForceVelocity { get; set; } |
132 | 173 | ||
133 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } | 174 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } |
@@ -146,9 +187,40 @@ public abstract class BSPhysObject : PhysicsActor | |||
146 | protected long CollidingStep { get; set; } | 187 | protected long CollidingStep { get; set; } |
147 | // The simulation step that last had a collision with the ground | 188 | // The simulation step that last had a collision with the ground |
148 | protected long CollidingGroundStep { get; set; } | 189 | protected long CollidingGroundStep { get; set; } |
190 | // The simulation step that last collided with an object | ||
191 | protected long CollidingObjectStep { get; set; } | ||
149 | // The collision flags we think are set in Bullet | 192 | // The collision flags we think are set in Bullet |
150 | protected CollisionFlags CurrentCollisionFlags { get; set; } | 193 | protected CollisionFlags CurrentCollisionFlags { get; set; } |
151 | 194 | ||
195 | public override bool IsColliding { | ||
196 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | ||
197 | set { | ||
198 | if (value) | ||
199 | CollidingStep = PhysicsScene.SimulationStep; | ||
200 | else | ||
201 | CollidingStep = 0; | ||
202 | } | ||
203 | } | ||
204 | public override bool CollidingGround { | ||
205 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | ||
206 | set | ||
207 | { | ||
208 | if (value) | ||
209 | CollidingGroundStep = PhysicsScene.SimulationStep; | ||
210 | else | ||
211 | CollidingGroundStep = 0; | ||
212 | } | ||
213 | } | ||
214 | public override bool CollidingObj { | ||
215 | get { return (CollidingObjectStep == PhysicsScene.SimulationStep); } | ||
216 | set { | ||
217 | if (value) | ||
218 | CollidingObjectStep = PhysicsScene.SimulationStep; | ||
219 | else | ||
220 | CollidingObjectStep = 0; | ||
221 | } | ||
222 | } | ||
223 | |||
152 | // The collisions that have been collected this tick | 224 | // The collisions that have been collected this tick |
153 | protected CollisionEventUpdate CollisionCollection; | 225 | protected CollisionEventUpdate CollisionCollection; |
154 | 226 | ||
@@ -160,12 +232,16 @@ public abstract class BSPhysObject : PhysicsActor | |||
160 | { | 232 | { |
161 | bool ret = false; | 233 | bool ret = false; |
162 | 234 | ||
163 | // The following lines make IsColliding() and IsCollidingGround() work | 235 | // The following lines make IsColliding(), CollidingGround() and CollidingObj work |
164 | CollidingStep = PhysicsScene.SimulationStep; | 236 | CollidingStep = PhysicsScene.SimulationStep; |
165 | if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) | 237 | if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) |
166 | { | 238 | { |
167 | CollidingGroundStep = PhysicsScene.SimulationStep; | 239 | CollidingGroundStep = PhysicsScene.SimulationStep; |
168 | } | 240 | } |
241 | else | ||
242 | { | ||
243 | CollidingObjectStep = PhysicsScene.SimulationStep; | ||
244 | } | ||
169 | 245 | ||
170 | // prims in the same linkset cannot collide with each other | 246 | // prims in the same linkset cannot collide with each other |
171 | if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID)) | 247 | if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID)) |
@@ -192,7 +268,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
192 | { | 268 | { |
193 | bool ret = true; | 269 | bool ret = true; |
194 | // If the 'no collision' call, force it to happen right now so quick collision_end | 270 | // If the 'no collision' call, force it to happen right now so quick collision_end |
195 | bool force = CollisionCollection.Count == 0; | 271 | bool force = (CollisionCollection.Count == 0); |
196 | 272 | ||
197 | // throttle the collisions to the number of milliseconds specified in the subscription | 273 | // throttle the collisions to the number of milliseconds specified in the subscription |
198 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) | 274 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) |
@@ -210,8 +286,10 @@ public abstract class BSPhysObject : PhysicsActor | |||
210 | // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); | 286 | // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); |
211 | base.SendCollisionUpdate(CollisionCollection); | 287 | base.SendCollisionUpdate(CollisionCollection); |
212 | 288 | ||
213 | // The collisionCollection structure is passed around in the simulator. | 289 | // The CollisionCollection instance is passed around in the simulator. |
214 | // Make sure we don't have a handle to that one and that a new one is used for next time. | 290 | // Make sure we don't have a handle to that one and that a new one is used for next time. |
291 | // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, | ||
292 | // a race condition is created for the other users of this instance. | ||
215 | CollisionCollection = new CollisionEventUpdate(); | 293 | CollisionCollection = new CollisionEventUpdate(); |
216 | } | 294 | } |
217 | return ret; | 295 | return ret; |
@@ -229,7 +307,8 @@ public abstract class BSPhysObject : PhysicsActor | |||
229 | 307 | ||
230 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() | 308 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() |
231 | { | 309 | { |
232 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 310 | if (PhysBody.HasPhysicalBody) |
311 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
233 | }); | 312 | }); |
234 | } | 313 | } |
235 | else | 314 | else |
@@ -243,7 +322,9 @@ public abstract class BSPhysObject : PhysicsActor | |||
243 | SubscribedEventsMs = 0; | 322 | SubscribedEventsMs = 0; |
244 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() | 323 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() |
245 | { | 324 | { |
246 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 325 | // Make sure there is a body there because sometimes destruction happens in an un-ideal order. |
326 | if (PhysBody.HasPhysicalBody) | ||
327 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
247 | }); | 328 | }); |
248 | } | 329 | } |
249 | // Return 'true' if the simulator wants collision events | 330 | // Return 'true' if the simulator wants collision events |
@@ -253,11 +334,57 @@ public abstract class BSPhysObject : PhysicsActor | |||
253 | 334 | ||
254 | #endregion // Collisions | 335 | #endregion // Collisions |
255 | 336 | ||
337 | #region Per Simulation Step actions | ||
338 | // There are some actions that must be performed for a physical object before each simulation step. | ||
339 | // These actions are optional so, rather than scanning all the physical objects and asking them | ||
340 | // if they have anything to do, a physical object registers for an event call before the step is performed. | ||
341 | // This bookkeeping makes it easy to add, remove and clean up after all these registrations. | ||
342 | private Dictionary<string, BSScene.PreStepAction> RegisteredActions = new Dictionary<string, BSScene.PreStepAction>(); | ||
343 | protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn) | ||
344 | { | ||
345 | string identifier = op + "-" + id.ToString(); | ||
346 | |||
347 | // Clean out any existing action | ||
348 | UnRegisterPreStepAction(op, id); | ||
349 | |||
350 | RegisteredActions[identifier] = actn; | ||
351 | PhysicsScene.BeforeStep += actn; | ||
352 | DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier); | ||
353 | } | ||
354 | |||
355 | // Unregister a pre step action. Safe to call if the action has not been registered. | ||
356 | protected void UnRegisterPreStepAction(string op, uint id) | ||
357 | { | ||
358 | string identifier = op + "-" + id.ToString(); | ||
359 | bool removed = false; | ||
360 | if (RegisteredActions.ContainsKey(identifier)) | ||
361 | { | ||
362 | PhysicsScene.BeforeStep -= RegisteredActions[identifier]; | ||
363 | RegisteredActions.Remove(identifier); | ||
364 | removed = true; | ||
365 | } | ||
366 | DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed); | ||
367 | } | ||
368 | |||
369 | protected void UnRegisterAllPreStepActions() | ||
370 | { | ||
371 | foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredActions) | ||
372 | { | ||
373 | PhysicsScene.BeforeStep -= kvp.Value; | ||
374 | } | ||
375 | RegisteredActions.Clear(); | ||
376 | DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID); | ||
377 | } | ||
378 | |||
379 | |||
380 | #endregion // Per Simulation Step actions | ||
381 | |||
256 | // High performance detailed logging routine used by the physical objects. | 382 | // High performance detailed logging routine used by the physical objects. |
257 | protected void DetailLog(string msg, params Object[] args) | 383 | protected void DetailLog(string msg, params Object[] args) |
258 | { | 384 | { |
259 | if (PhysicsScene.PhysicsLogging.Enabled) | 385 | if (PhysicsScene.PhysicsLogging.Enabled) |
260 | PhysicsScene.DetailLog(msg, args); | 386 | PhysicsScene.DetailLog(msg, args); |
261 | } | 387 | } |
388 | |||
262 | } | 389 | } |
263 | } | 390 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs index 20f5180..65be52a 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs | |||
@@ -59,12 +59,6 @@ public class BSPlugin : IPhysicsPlugin | |||
59 | { | 59 | { |
60 | if (_mScene == null) | 60 | if (_mScene == null) |
61 | { | 61 | { |
62 | if (Util.IsWindows()) | ||
63 | Util.LoadArchSpecificWindowsDll("BulletSim.dll"); | ||
64 | // If not Windows, loading is performed by the | ||
65 | // Mono loader as specified in | ||
66 | // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". | ||
67 | |||
68 | _mScene = new BSScene(sceneIdentifier); | 62 | _mScene = new BSScene(sceneIdentifier); |
69 | } | 63 | } |
70 | return (_mScene); | 64 | return (_mScene); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 2b3fa25..94b63e5 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -45,7 +45,6 @@ public sealed class BSPrim : BSPhysObject | |||
45 | private static readonly string LogHeader = "[BULLETS PRIM]"; | 45 | private static readonly string LogHeader = "[BULLETS PRIM]"; |
46 | 46 | ||
47 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. | 47 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. |
48 | // Often Scale is unity because the meshmerizer will apply _size when creating the mesh. | ||
49 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user | 48 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user |
50 | 49 | ||
51 | private bool _grabbed; | 50 | private bool _grabbed; |
@@ -67,9 +66,6 @@ public sealed class BSPrim : BSPhysObject | |||
67 | private float _restitution; | 66 | private float _restitution; |
68 | private bool _setAlwaysRun; | 67 | private bool _setAlwaysRun; |
69 | private bool _throttleUpdates; | 68 | private bool _throttleUpdates; |
70 | private bool _isColliding; | ||
71 | private bool _collidingGround; | ||
72 | private bool _collidingObj; | ||
73 | private bool _floatOnWater; | 69 | private bool _floatOnWater; |
74 | private OMV.Vector3 _rotationalVelocity; | 70 | private OMV.Vector3 _rotationalVelocity; |
75 | private bool _kinematic; | 71 | private bool _kinematic; |
@@ -77,13 +73,14 @@ public sealed class BSPrim : BSPhysObject | |||
77 | 73 | ||
78 | private BSDynamics _vehicle; | 74 | private BSDynamics _vehicle; |
79 | 75 | ||
76 | private BSVMotor _targetMotor; | ||
80 | private OMV.Vector3 _PIDTarget; | 77 | private OMV.Vector3 _PIDTarget; |
81 | private bool _usePID; | ||
82 | private float _PIDTau; | 78 | private float _PIDTau; |
83 | private bool _useHoverPID; | 79 | |
80 | private BSFMotor _hoverMotor; | ||
84 | private float _PIDHoverHeight; | 81 | private float _PIDHoverHeight; |
85 | private PIDHoverType _PIDHoverType; | 82 | private PIDHoverType _PIDHoverType; |
86 | private float _PIDHoverTao; | 83 | private float _PIDHoverTau; |
87 | 84 | ||
88 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | 85 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, |
89 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | 86 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) |
@@ -93,23 +90,27 @@ public sealed class BSPrim : BSPhysObject | |||
93 | _physicsActorType = (int)ActorTypes.Prim; | 90 | _physicsActorType = (int)ActorTypes.Prim; |
94 | _position = pos; | 91 | _position = pos; |
95 | _size = size; | 92 | _size = size; |
96 | Scale = size; // the scale will be set by CreateGeom depending on object type | 93 | Scale = size; // prims are the size the user wants them to be (different for BSCharactes). |
97 | _orientation = rotation; | 94 | _orientation = rotation; |
98 | _buoyancy = 1f; | 95 | _buoyancy = 0f; |
99 | _velocity = OMV.Vector3.Zero; | 96 | _velocity = OMV.Vector3.Zero; |
100 | _rotationalVelocity = OMV.Vector3.Zero; | 97 | _rotationalVelocity = OMV.Vector3.Zero; |
101 | BaseShape = pbs; | 98 | BaseShape = pbs; |
102 | _isPhysical = pisPhysical; | 99 | _isPhysical = pisPhysical; |
103 | _isVolumeDetect = false; | 100 | _isVolumeDetect = false; |
104 | _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material | 101 | |
105 | _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material | 102 | // Someday set default attributes based on the material but, for now, we don't know the prim material yet. |
103 | // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical); | ||
104 | _density = PhysicsScene.Params.defaultDensity; | ||
105 | _friction = PhysicsScene.Params.defaultFriction; | ||
106 | _restitution = PhysicsScene.Params.defaultRestitution; | 106 | _restitution = PhysicsScene.Params.defaultRestitution; |
107 | |||
107 | _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness | 108 | _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness |
109 | |||
108 | _mass = CalculateMass(); | 110 | _mass = CalculateMass(); |
109 | 111 | ||
110 | // No body or shape yet | 112 | // Cause linkset variables to be initialized (like mass) |
111 | PhysBody = new BulletBody(LocalID, IntPtr.Zero); | 113 | Linkset.Refresh(this); |
112 | PhysShape = new BulletShape(IntPtr.Zero); | ||
113 | 114 | ||
114 | DetailLog("{0},BSPrim.constructor,call", LocalID); | 115 | DetailLog("{0},BSPrim.constructor,call", LocalID); |
115 | // do the actual object creation at taint time | 116 | // do the actual object creation at taint time |
@@ -117,7 +118,7 @@ public sealed class BSPrim : BSPhysObject | |||
117 | { | 118 | { |
118 | CreateGeomAndObject(true); | 119 | CreateGeomAndObject(true); |
119 | 120 | ||
120 | CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr); | 121 | CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody); |
121 | }); | 122 | }); |
122 | } | 123 | } |
123 | 124 | ||
@@ -125,6 +126,7 @@ public sealed class BSPrim : BSPhysObject | |||
125 | public override void Destroy() | 126 | public override void Destroy() |
126 | { | 127 | { |
127 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); | 128 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); |
129 | base.Destroy(); | ||
128 | 130 | ||
129 | // Undo any links between me and any other object | 131 | // Undo any links between me and any other object |
130 | BSPhysObject parentBefore = Linkset.LinksetRoot; | 132 | BSPhysObject parentBefore = Linkset.LinksetRoot; |
@@ -143,7 +145,9 @@ public sealed class BSPrim : BSPhysObject | |||
143 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); | 145 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); |
144 | // If there are physical body and shape, release my use of same. | 146 | // If there are physical body and shape, release my use of same. |
145 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | 147 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); |
148 | PhysBody.Clear(); | ||
146 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | 149 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); |
150 | PhysShape.Clear(); | ||
147 | }); | 151 | }); |
148 | } | 152 | } |
149 | 153 | ||
@@ -157,12 +161,10 @@ public sealed class BSPrim : BSPhysObject | |||
157 | // We presume the scale and size are the same. If scale must be changed for | 161 | // We presume the scale and size are the same. If scale must be changed for |
158 | // the physical shape, that is done when the geometry is built. | 162 | // the physical shape, that is done when the geometry is built. |
159 | _size = value; | 163 | _size = value; |
164 | Scale = _size; | ||
160 | ForceBodyShapeRebuild(false); | 165 | ForceBodyShapeRebuild(false); |
161 | } | 166 | } |
162 | } | 167 | } |
163 | // Scale is what we set in the physics engine. It is different than 'size' in that | ||
164 | // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>. | ||
165 | public override OMV.Vector3 Scale { get; set; } | ||
166 | 168 | ||
167 | public override PrimitiveBaseShape Shape { | 169 | public override PrimitiveBaseShape Shape { |
168 | set { | 170 | set { |
@@ -189,13 +191,17 @@ public sealed class BSPrim : BSPhysObject | |||
189 | } | 191 | } |
190 | } | 192 | } |
191 | public override bool Selected { | 193 | public override bool Selected { |
192 | set { | 194 | set |
193 | _isSelected = value; | 195 | { |
194 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() | 196 | if (value != _isSelected) |
195 | { | 197 | { |
196 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | 198 | _isSelected = value; |
197 | SetObjectDynamic(false); | 199 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() |
198 | }); | 200 | { |
201 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | ||
202 | SetObjectDynamic(false); | ||
203 | }); | ||
204 | } | ||
199 | } | 205 | } |
200 | } | 206 | } |
201 | public override void CrossingFailure() { return; } | 207 | public override void CrossingFailure() { return; } |
@@ -244,7 +250,8 @@ public sealed class BSPrim : BSPhysObject | |||
244 | // Zero some other properties in the physics engine | 250 | // Zero some other properties in the physics engine |
245 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 251 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
246 | { | 252 | { |
247 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | 253 | if (PhysBody.HasPhysicalBody) |
254 | PhysicsScene.PE.ClearAllForces(PhysBody); | ||
248 | }); | 255 | }); |
249 | } | 256 | } |
250 | public override void ZeroAngularMotion(bool inTaintTime) | 257 | public override void ZeroAngularMotion(bool inTaintTime) |
@@ -253,8 +260,12 @@ public sealed class BSPrim : BSPhysObject | |||
253 | // Zero some other properties in the physics engine | 260 | // Zero some other properties in the physics engine |
254 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 261 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
255 | { | 262 | { |
256 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 263 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); |
257 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 264 | if (PhysBody.HasPhysicalBody) |
265 | { | ||
266 | PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); | ||
267 | PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | ||
268 | } | ||
258 | }); | 269 | }); |
259 | } | 270 | } |
260 | 271 | ||
@@ -271,41 +282,50 @@ public sealed class BSPrim : BSPhysObject | |||
271 | } | 282 | } |
272 | public override OMV.Vector3 Position { | 283 | public override OMV.Vector3 Position { |
273 | get { | 284 | get { |
285 | /* NOTE: this refetch is not necessary. The simulator knows about linkset children | ||
286 | * and does not fetch this position info for children. Thus this is commented out. | ||
274 | // child prims move around based on their parent. Need to get the latest location | 287 | // child prims move around based on their parent. Need to get the latest location |
275 | if (!Linkset.IsRoot(this)) | 288 | if (!Linkset.IsRoot(this)) |
276 | _position = Linkset.Position(this); | 289 | _position = Linkset.PositionGet(this); |
290 | */ | ||
277 | 291 | ||
278 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. | 292 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. |
279 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | 293 | // _position = PhysicsScene.PE.GetObjectPosition2(PhysicsScene.World, BSBody); |
280 | return _position; | 294 | return _position; |
281 | } | 295 | } |
282 | set { | 296 | set { |
283 | // If the position must be forced into the physics engine, use ForcePosition. | 297 | // If the position must be forced into the physics engine, use ForcePosition. |
298 | // All positions are given in world positions. | ||
284 | if (_position == value) | 299 | if (_position == value) |
285 | { | 300 | { |
301 | DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation); | ||
286 | return; | 302 | return; |
287 | } | 303 | } |
288 | _position = value; | 304 | _position = value; |
289 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? | ||
290 | PositionSanityCheck(false); | 305 | PositionSanityCheck(false); |
306 | |||
307 | // A linkset might need to know if a component information changed. | ||
308 | Linkset.UpdateProperties(this, false); | ||
309 | |||
291 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() | 310 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() |
292 | { | 311 | { |
293 | // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 312 | DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
294 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 313 | ForcePosition = _position; |
295 | ActivateIfPhysical(false); | ||
296 | }); | 314 | }); |
297 | } | 315 | } |
298 | } | 316 | } |
299 | public override OMV.Vector3 ForcePosition { | 317 | public override OMV.Vector3 ForcePosition { |
300 | get { | 318 | get { |
301 | _position = BulletSimAPI.GetPosition2(PhysBody.ptr); | 319 | _position = PhysicsScene.PE.GetPosition(PhysBody); |
302 | return _position; | 320 | return _position; |
303 | } | 321 | } |
304 | set { | 322 | set { |
305 | _position = value; | 323 | _position = value; |
306 | // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better. | 324 | if (PhysBody.HasPhysicalBody) |
307 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 325 | { |
308 | ActivateIfPhysical(false); | 326 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); |
327 | ActivateIfPhysical(false); | ||
328 | } | ||
309 | } | 329 | } |
310 | } | 330 | } |
311 | 331 | ||
@@ -316,51 +336,58 @@ public sealed class BSPrim : BSPhysObject | |||
316 | { | 336 | { |
317 | bool ret = false; | 337 | bool ret = false; |
318 | 338 | ||
339 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) | ||
340 | { | ||
341 | // The physical object is out of the known/simulated area. | ||
342 | // Upper levels of code will handle the transition to other areas so, for | ||
343 | // the time, we just ignore the position. | ||
344 | return ret; | ||
345 | } | ||
346 | |||
319 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | 347 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); |
320 | OMV.Vector3 upForce = OMV.Vector3.Zero; | 348 | OMV.Vector3 upForce = OMV.Vector3.Zero; |
321 | if (Position.Z < terrainHeight) | 349 | if (RawPosition.Z < terrainHeight) |
322 | { | 350 | { |
323 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | 351 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); |
324 | float targetHeight = terrainHeight + (Size.Z / 2f); | 352 | float targetHeight = terrainHeight + (Size.Z / 2f); |
325 | // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. | 353 | // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. |
326 | upForce.Z = (terrainHeight - Position.Z) * 1f; | 354 | upForce.Z = (terrainHeight - RawPosition.Z) * 1f; |
327 | ret = true; | 355 | ret = true; |
328 | } | 356 | } |
329 | 357 | ||
330 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 358 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
331 | { | 359 | { |
332 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | 360 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
333 | // TODO: a floating motor so object will bob in the water | 361 | // TODO: a floating motor so object will bob in the water |
334 | if (Math.Abs(Position.Z - waterHeight) > 0.1f) | 362 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) |
335 | { | 363 | { |
336 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. | 364 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. |
337 | upForce.Z = (waterHeight - Position.Z) * 1f; | 365 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; |
338 | ret = true; | 366 | ret = true; |
339 | } | 367 | } |
340 | } | 368 | } |
341 | 369 | ||
342 | // TODO: check for out of bounds | ||
343 | |||
344 | // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. | 370 | // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. |
371 | // TODO: This should be intergrated with a geneal physics action mechanism. | ||
372 | // TODO: This should be moderated with PID'ness. | ||
345 | if (ret) | 373 | if (ret) |
346 | { | 374 | { |
347 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() | 375 | // Apply upforce and overcome gravity. |
348 | { | 376 | OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; |
349 | // Apply upforce and overcome gravity. | 377 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); |
350 | ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity; | 378 | AddForce(correctionForce, false, inTaintTime); |
351 | }); | ||
352 | } | 379 | } |
353 | return ret; | 380 | return ret; |
354 | } | 381 | } |
355 | 382 | ||
356 | // Return the effective mass of the object. | 383 | // Return the effective mass of the object. |
357 | // If there are multiple items in the linkset, add them together for the root | 384 | // The definition of this call is to return the mass of the prim. |
385 | // If the simulator cares about the mass of the linkset, it will sum it itself. | ||
358 | public override float Mass | 386 | public override float Mass |
359 | { | 387 | { |
360 | get | 388 | get |
361 | { | 389 | { |
362 | return Linkset.LinksetMass; | 390 | return _mass; |
363 | // return _mass; | ||
364 | } | 391 | } |
365 | } | 392 | } |
366 | 393 | ||
@@ -370,25 +397,64 @@ public sealed class BSPrim : BSPhysObject | |||
370 | } | 397 | } |
371 | // Set the physical mass to the passed mass. | 398 | // Set the physical mass to the passed mass. |
372 | // Note that this does not change _mass! | 399 | // Note that this does not change _mass! |
373 | public override void UpdatePhysicalMassProperties(float physMass) | 400 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) |
374 | { | 401 | { |
375 | if (IsStatic) | 402 | if (PhysBody.HasPhysicalBody) |
376 | { | ||
377 | Inertia = OMV.Vector3.Zero; | ||
378 | BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia); | ||
379 | BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); | ||
380 | } | ||
381 | else | ||
382 | { | 403 | { |
383 | Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); | 404 | if (IsStatic) |
384 | BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia); | 405 | { |
385 | BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); | 406 | PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity); |
386 | // center of mass is at the zero of the object | 407 | Inertia = OMV.Vector3.Zero; |
387 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation); | 408 | PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia); |
388 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, Inertia); | 409 | PhysicsScene.PE.UpdateInertiaTensor(PhysBody); |
410 | } | ||
411 | else | ||
412 | { | ||
413 | OMV.Vector3 grav = ComputeGravity(); | ||
414 | |||
415 | if (inWorld) | ||
416 | { | ||
417 | // Changing interesting properties doesn't change proxy and collision cache | ||
418 | // information. The Bullet solution is to re-add the object to the world | ||
419 | // after parameters are changed. | ||
420 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | ||
421 | } | ||
422 | |||
423 | // The computation of mass props requires gravity to be set on the object. | ||
424 | PhysicsScene.PE.SetGravity(PhysBody, grav); | ||
425 | |||
426 | Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); | ||
427 | PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); | ||
428 | PhysicsScene.PE.UpdateInertiaTensor(PhysBody); | ||
429 | |||
430 | // center of mass is at the zero of the object | ||
431 | // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(PhysBody, ForcePosition, ForceOrientation); | ||
432 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", LocalID, physMass, Inertia, grav, inWorld); | ||
433 | |||
434 | if (inWorld) | ||
435 | { | ||
436 | AddObjectToPhysicalWorld(); | ||
437 | } | ||
438 | |||
439 | // Must set gravity after it has been added to the world because, for unknown reasons, | ||
440 | // adding the object resets the object's gravity to world gravity | ||
441 | PhysicsScene.PE.SetGravity(PhysBody, grav); | ||
442 | |||
443 | } | ||
389 | } | 444 | } |
390 | } | 445 | } |
391 | 446 | ||
447 | // Return what gravity should be set to this very moment | ||
448 | private OMV.Vector3 ComputeGravity() | ||
449 | { | ||
450 | OMV.Vector3 ret = PhysicsScene.DefaultGravity; | ||
451 | |||
452 | if (!IsStatic) | ||
453 | ret *= (1f - Buoyancy); | ||
454 | |||
455 | return ret; | ||
456 | } | ||
457 | |||
392 | // Is this used? | 458 | // Is this used? |
393 | public override OMV.Vector3 CenterOfMass | 459 | public override OMV.Vector3 CenterOfMass |
394 | { | 460 | { |
@@ -405,11 +471,26 @@ public sealed class BSPrim : BSPhysObject | |||
405 | get { return _force; } | 471 | get { return _force; } |
406 | set { | 472 | set { |
407 | _force = value; | 473 | _force = value; |
408 | PhysicsScene.TaintedObject("BSPrim.setForce", delegate() | 474 | if (_force != OMV.Vector3.Zero) |
409 | { | 475 | { |
410 | // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); | 476 | // If the force is non-zero, it must be reapplied each tick because |
411 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 477 | // Bullet clears the forces applied last frame. |
412 | }); | 478 | RegisterPreStepAction("BSPrim.setForce", LocalID, |
479 | delegate(float timeStep) | ||
480 | { | ||
481 | DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); | ||
482 | if (PhysBody.HasPhysicalBody) | ||
483 | { | ||
484 | PhysicsScene.PE.ApplyCentralForce(PhysBody, _force); | ||
485 | ActivateIfPhysical(false); | ||
486 | } | ||
487 | } | ||
488 | ); | ||
489 | } | ||
490 | else | ||
491 | { | ||
492 | UnRegisterPreStepAction("BSPrim.setForce", LocalID); | ||
493 | } | ||
413 | } | 494 | } |
414 | } | 495 | } |
415 | 496 | ||
@@ -420,15 +501,18 @@ public sealed class BSPrim : BSPhysObject | |||
420 | set { | 501 | set { |
421 | Vehicle type = (Vehicle)value; | 502 | Vehicle type = (Vehicle)value; |
422 | 503 | ||
423 | // Tell the scene about the vehicle so it will get processing each frame. | ||
424 | PhysicsScene.VehicleInSceneTypeChanged(this, type); | ||
425 | |||
426 | PhysicsScene.TaintedObject("setVehicleType", delegate() | 504 | PhysicsScene.TaintedObject("setVehicleType", delegate() |
427 | { | 505 | { |
428 | // Done at taint time so we're sure the physics engine is not using the variables | 506 | // Done at taint time so we're sure the physics engine is not using the variables |
429 | // Vehicle code changes the parameters for this vehicle type. | 507 | // Vehicle code changes the parameters for this vehicle type. |
430 | _vehicle.ProcessTypeChange(type); | 508 | _vehicle.ProcessTypeChange(type); |
431 | ActivateIfPhysical(false); | 509 | ActivateIfPhysical(false); |
510 | |||
511 | // If an active vehicle, register the vehicle code to be called before each step | ||
512 | if (_vehicle.Type == Vehicle.TYPE_NONE) | ||
513 | UnRegisterPreStepAction("BSPrim.Vehicle", LocalID); | ||
514 | else | ||
515 | RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step); | ||
432 | }); | 516 | }); |
433 | } | 517 | } |
434 | } | 518 | } |
@@ -464,23 +548,6 @@ public sealed class BSPrim : BSPhysObject | |||
464 | }); | 548 | }); |
465 | } | 549 | } |
466 | 550 | ||
467 | // Called each simulation step to advance vehicle characteristics. | ||
468 | // Called from Scene when doing simulation step so we're in taint processing time. | ||
469 | public override void StepVehicle(float timeStep) | ||
470 | { | ||
471 | if (IsPhysical && _vehicle.IsActive) | ||
472 | { | ||
473 | _vehicle.Step(timeStep); | ||
474 | /* // TEST TEST DEBUG DEBUG -- trying to reduce the extra action of Bullet simulation step | ||
475 | PhysicsScene.PostTaintObject("BSPrim.StepVehicles", LocalID, delegate() | ||
476 | { | ||
477 | // This resets the interpolation values and recomputes the tensor variables | ||
478 | BulletSimAPI.SetCenterOfMassByPosRot2(BSBody.ptr, ForcePosition, ForceOrientation); | ||
479 | }); | ||
480 | */ | ||
481 | } | ||
482 | } | ||
483 | |||
484 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | 551 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more |
485 | public override void SetVolumeDetect(int param) { | 552 | public override void SetVolumeDetect(int param) { |
486 | bool newValue = (param != 0); | 553 | bool newValue = (param != 0); |
@@ -495,6 +562,11 @@ public sealed class BSPrim : BSPhysObject | |||
495 | } | 562 | } |
496 | return; | 563 | return; |
497 | } | 564 | } |
565 | public OMV.Vector3 RawVelocity | ||
566 | { | ||
567 | get { return _velocity; } | ||
568 | set { _velocity = value; } | ||
569 | } | ||
498 | public override OMV.Vector3 Velocity { | 570 | public override OMV.Vector3 Velocity { |
499 | get { return _velocity; } | 571 | get { return _velocity; } |
500 | set { | 572 | set { |
@@ -502,22 +574,43 @@ public sealed class BSPrim : BSPhysObject | |||
502 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() | 574 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() |
503 | { | 575 | { |
504 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); | 576 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); |
505 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | 577 | ForceVelocity = _velocity; |
506 | }); | 578 | }); |
507 | } | 579 | } |
508 | } | 580 | } |
509 | public override OMV.Vector3 ForceVelocity { | 581 | public override OMV.Vector3 ForceVelocity { |
510 | get { return _velocity; } | 582 | get { return _velocity; } |
511 | set { | 583 | set { |
584 | PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); | ||
585 | |||
512 | _velocity = value; | 586 | _velocity = value; |
513 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | 587 | if (PhysBody.HasPhysicalBody) |
588 | { | ||
589 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); | ||
590 | ActivateIfPhysical(false); | ||
591 | } | ||
514 | } | 592 | } |
515 | } | 593 | } |
516 | public override OMV.Vector3 Torque { | 594 | public override OMV.Vector3 Torque { |
517 | get { return _torque; } | 595 | get { return _torque; } |
518 | set { | 596 | set { |
519 | _torque = value; | 597 | _torque = value; |
520 | AddAngularForce(_torque, false, false); | 598 | if (_torque != OMV.Vector3.Zero) |
599 | { | ||
600 | // If the torque is non-zero, it must be reapplied each tick because | ||
601 | // Bullet clears the forces applied last frame. | ||
602 | RegisterPreStepAction("BSPrim.setTorque", LocalID, | ||
603 | delegate(float timeStep) | ||
604 | { | ||
605 | if (PhysBody.HasPhysicalBody) | ||
606 | AddAngularForce(_torque, false, true); | ||
607 | } | ||
608 | ); | ||
609 | } | ||
610 | else | ||
611 | { | ||
612 | UnRegisterPreStepAction("BSPrim.setTorque", LocalID); | ||
613 | } | ||
521 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); | 614 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); |
522 | } | 615 | } |
523 | } | 616 | } |
@@ -537,23 +630,32 @@ public sealed class BSPrim : BSPhysObject | |||
537 | } | 630 | } |
538 | public override OMV.Quaternion Orientation { | 631 | public override OMV.Quaternion Orientation { |
539 | get { | 632 | get { |
633 | /* NOTE: this refetch is not necessary. The simulator knows about linkset children | ||
634 | * and does not fetch this position info for children. Thus this is commented out. | ||
540 | // Children move around because tied to parent. Get a fresh value. | 635 | // Children move around because tied to parent. Get a fresh value. |
541 | if (!Linkset.IsRoot(this)) | 636 | if (!Linkset.IsRoot(this)) |
542 | { | 637 | { |
543 | _orientation = Linkset.Orientation(this); | 638 | _orientation = Linkset.OrientationGet(this); |
544 | } | 639 | } |
640 | */ | ||
545 | return _orientation; | 641 | return _orientation; |
546 | } | 642 | } |
547 | set { | 643 | set { |
548 | if (_orientation == value) | 644 | if (_orientation == value) |
549 | return; | 645 | return; |
550 | _orientation = value; | 646 | _orientation = value; |
551 | // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? | 647 | |
648 | // A linkset might need to know if a component information changed. | ||
649 | Linkset.UpdateProperties(this, false); | ||
650 | |||
552 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() | 651 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() |
553 | { | 652 | { |
554 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | 653 | if (PhysBody.HasPhysicalBody) |
555 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 654 | { |
556 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 655 | // _position = PhysicsScene.PE.GetObjectPosition(PhysicsScene.World, BSBody); |
656 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
657 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
658 | } | ||
557 | }); | 659 | }); |
558 | } | 660 | } |
559 | } | 661 | } |
@@ -562,13 +664,13 @@ public sealed class BSPrim : BSPhysObject | |||
562 | { | 664 | { |
563 | get | 665 | get |
564 | { | 666 | { |
565 | _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); | 667 | _orientation = PhysicsScene.PE.GetOrientation(PhysBody); |
566 | return _orientation; | 668 | return _orientation; |
567 | } | 669 | } |
568 | set | 670 | set |
569 | { | 671 | { |
570 | _orientation = value; | 672 | _orientation = value; |
571 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 673 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); |
572 | } | 674 | } |
573 | } | 675 | } |
574 | public override int PhysicsActorType { | 676 | public override int PhysicsActorType { |
@@ -583,7 +685,7 @@ public sealed class BSPrim : BSPhysObject | |||
583 | _isPhysical = value; | 685 | _isPhysical = value; |
584 | PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() | 686 | PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() |
585 | { | 687 | { |
586 | // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); | 688 | DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); |
587 | SetObjectDynamic(true); | 689 | SetObjectDynamic(true); |
588 | // whether phys-to-static or static-to-phys, the object is not moving. | 690 | // whether phys-to-static or static-to-phys, the object is not moving. |
589 | ZeroMotion(true); | 691 | ZeroMotion(true); |
@@ -624,7 +726,7 @@ public sealed class BSPrim : BSPhysObject | |||
624 | 726 | ||
625 | // Mangling all the physical properties requires the object not be in the physical world. | 727 | // Mangling all the physical properties requires the object not be in the physical world. |
626 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). | 728 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). |
627 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | 729 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); |
628 | 730 | ||
629 | // Set up the object physicalness (does gravity and collisions move this object) | 731 | // Set up the object physicalness (does gravity and collisions move this object) |
630 | MakeDynamic(IsStatic); | 732 | MakeDynamic(IsStatic); |
@@ -638,16 +740,10 @@ public sealed class BSPrim : BSPhysObject | |||
638 | // Make solid or not (do things bounce off or pass through this object). | 740 | // Make solid or not (do things bounce off or pass through this object). |
639 | MakeSolid(IsSolid); | 741 | MakeSolid(IsSolid); |
640 | 742 | ||
641 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | 743 | AddObjectToPhysicalWorld(); |
642 | 744 | ||
643 | // Rebuild its shape | 745 | // Rebuild its shape |
644 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | 746 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); |
645 | |||
646 | // Collision filter can be set only when the object is in the world | ||
647 | if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0) | ||
648 | { | ||
649 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask); | ||
650 | } | ||
651 | 747 | ||
652 | // Recompute any linkset parameters. | 748 | // Recompute any linkset parameters. |
653 | // When going from non-physical to physical, this re-enables the constraints that | 749 | // When going from non-physical to physical, this re-enables the constraints that |
@@ -655,8 +751,8 @@ public sealed class BSPrim : BSPhysObject | |||
655 | // For compound based linksets, this enables and disables interactions of the children. | 751 | // For compound based linksets, this enables and disables interactions of the children. |
656 | Linkset.Refresh(this); | 752 | Linkset.Refresh(this); |
657 | 753 | ||
658 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", | 754 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", |
659 | LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape); | 755 | LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); |
660 | } | 756 | } |
661 | 757 | ||
662 | // "Making dynamic" means changing to and from static. | 758 | // "Making dynamic" means changing to and from static. |
@@ -669,74 +765,80 @@ public sealed class BSPrim : BSPhysObject | |||
669 | if (makeStatic) | 765 | if (makeStatic) |
670 | { | 766 | { |
671 | // Become a Bullet 'static' object type | 767 | // Become a Bullet 'static' object type |
672 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 768 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); |
673 | // Stop all movement | 769 | // Stop all movement |
674 | ZeroMotion(true); | 770 | ZeroMotion(true); |
675 | // Center of mass is at the center of the object | 771 | |
676 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); | 772 | // Set various physical properties so other object interact properly |
773 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); | ||
774 | PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction); | ||
775 | PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution); | ||
776 | |||
677 | // Mass is zero which disables a bunch of physics stuff in Bullet | 777 | // Mass is zero which disables a bunch of physics stuff in Bullet |
678 | UpdatePhysicalMassProperties(0f); | 778 | UpdatePhysicalMassProperties(0f, false); |
679 | // Set collision detection parameters | 779 | // Set collision detection parameters |
680 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | 780 | if (BSParam.CcdMotionThreshold > 0f) |
681 | { | 781 | { |
682 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | 782 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
683 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | 783 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
684 | } | 784 | } |
685 | // There can be special things needed for implementing linksets | 785 | |
686 | Linkset.MakeStatic(this); | ||
687 | // The activation state is 'disabled' so Bullet will not try to act on it. | 786 | // The activation state is 'disabled' so Bullet will not try to act on it. |
688 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | 787 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); |
689 | // Start it out sleeping and physical actions could wake it up. | 788 | // Start it out sleeping and physical actions could wake it up. |
690 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); | 789 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); |
790 | |||
791 | // This collides like a static object | ||
792 | PhysBody.collisionType = CollisionType.Static; | ||
691 | 793 | ||
692 | PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; | 794 | // There can be special things needed for implementing linksets |
693 | PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; | 795 | Linkset.MakeStatic(this); |
694 | } | 796 | } |
695 | else | 797 | else |
696 | { | 798 | { |
697 | // Not a Bullet static object | 799 | // Not a Bullet static object |
698 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 800 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); |
699 | 801 | ||
700 | // Set various physical properties so internal dynamic properties will get computed correctly as they are set | 802 | // Set various physical properties so other object interact properly |
701 | BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); | 803 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true); |
702 | BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); | 804 | PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction); |
805 | PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution); | ||
703 | 806 | ||
704 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 | 807 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 |
705 | // Since this can be called multiple times, only zero forces when becoming physical | 808 | // Since this can be called multiple times, only zero forces when becoming physical |
706 | // BulletSimAPI.ClearAllForces2(BSBody.ptr); | 809 | // PhysicsScene.PE.ClearAllForces(BSBody); |
707 | 810 | ||
708 | // For good measure, make sure the transform is set through to the motion state | 811 | // For good measure, make sure the transform is set through to the motion state |
709 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 812 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); |
710 | 813 | ||
711 | // Center of mass is at the center of the object | 814 | // Center of mass is at the center of the object |
712 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); | 815 | // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(Linkset.LinksetRoot.PhysBody, _position, _orientation); |
713 | 816 | ||
714 | // A dynamic object has mass | 817 | // A dynamic object has mass |
715 | UpdatePhysicalMassProperties(RawMass); | 818 | UpdatePhysicalMassProperties(RawMass, false); |
716 | 819 | ||
717 | // Set collision detection parameters | 820 | // Set collision detection parameters |
718 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | 821 | if (BSParam.CcdMotionThreshold > 0f) |
719 | { | 822 | { |
720 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | 823 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
721 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | 824 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
722 | } | 825 | } |
723 | 826 | ||
724 | // Various values for simulation limits | 827 | // Various values for simulation limits |
725 | BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); | 828 | PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); |
726 | BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime); | 829 | PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); |
727 | BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); | 830 | PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); |
728 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); | 831 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
729 | 832 | ||
730 | // There might be special things needed for implementing linksets. | 833 | // This collides like an object. |
731 | Linkset.MakeDynamic(this); | 834 | PhysBody.collisionType = CollisionType.Dynamic; |
732 | 835 | ||
733 | // Force activation of the object so Bullet will act on it. | 836 | // Force activation of the object so Bullet will act on it. |
734 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. | 837 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. |
735 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); | 838 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); |
736 | // BulletSimAPI.Activate2(BSBody.ptr, true); | ||
737 | 839 | ||
738 | PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; | 840 | // There might be special things needed for implementing linksets. |
739 | PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; | 841 | Linkset.MakeDynamic(this); |
740 | } | 842 | } |
741 | } | 843 | } |
742 | 844 | ||
@@ -746,7 +848,7 @@ public sealed class BSPrim : BSPhysObject | |||
746 | // the functions after this one set up the state of a possibly newly created collision body. | 848 | // the functions after this one set up the state of a possibly newly created collision body. |
747 | private void MakeSolid(bool makeSolid) | 849 | private void MakeSolid(bool makeSolid) |
748 | { | 850 | { |
749 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr); | 851 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody); |
750 | if (makeSolid) | 852 | if (makeSolid) |
751 | { | 853 | { |
752 | // Verify the previous code created the correct shape for this type of thing. | 854 | // Verify the previous code created the correct shape for this type of thing. |
@@ -754,7 +856,7 @@ public sealed class BSPrim : BSPhysObject | |||
754 | { | 856 | { |
755 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); | 857 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); |
756 | } | 858 | } |
757 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 859 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
758 | } | 860 | } |
759 | else | 861 | else |
760 | { | 862 | { |
@@ -762,9 +864,10 @@ public sealed class BSPrim : BSPhysObject | |||
762 | { | 864 | { |
763 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | 865 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); |
764 | } | 866 | } |
765 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 867 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
766 | PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; | 868 | |
767 | PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; | 869 | // Change collision info from a static object to a ghosty collision object |
870 | PhysBody.collisionType = CollisionType.VolumeDetect; | ||
768 | } | 871 | } |
769 | } | 872 | } |
770 | 873 | ||
@@ -773,8 +876,8 @@ public sealed class BSPrim : BSPhysObject | |||
773 | // Called in taint-time!! | 876 | // Called in taint-time!! |
774 | private void ActivateIfPhysical(bool forceIt) | 877 | private void ActivateIfPhysical(bool forceIt) |
775 | { | 878 | { |
776 | if (IsPhysical) | 879 | if (IsPhysical && PhysBody.HasPhysicalBody) |
777 | BulletSimAPI.Activate2(PhysBody.ptr, forceIt); | 880 | PhysicsScene.PE.Activate(PhysBody, forceIt); |
778 | } | 881 | } |
779 | 882 | ||
780 | // Turn on or off the flag controlling whether collision events are returned to the simulator. | 883 | // Turn on or off the flag controlling whether collision events are returned to the simulator. |
@@ -782,11 +885,27 @@ public sealed class BSPrim : BSPhysObject | |||
782 | { | 885 | { |
783 | if (wantsCollisionEvents) | 886 | if (wantsCollisionEvents) |
784 | { | 887 | { |
785 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 888 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
889 | } | ||
890 | else | ||
891 | { | ||
892 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
893 | } | ||
894 | } | ||
895 | |||
896 | // Add me to the physical world. | ||
897 | // Object MUST NOT already be in the world. | ||
898 | // This routine exists because some assorted properties get mangled by adding to the world. | ||
899 | internal void AddObjectToPhysicalWorld() | ||
900 | { | ||
901 | if (PhysBody.HasPhysicalBody) | ||
902 | { | ||
903 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); | ||
786 | } | 904 | } |
787 | else | 905 | else |
788 | { | 906 | { |
789 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 907 | m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID); |
908 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType); | ||
790 | } | 909 | } |
791 | } | 910 | } |
792 | 911 | ||
@@ -805,18 +924,6 @@ public sealed class BSPrim : BSPhysObject | |||
805 | get { return _throttleUpdates; } | 924 | get { return _throttleUpdates; } |
806 | set { _throttleUpdates = value; } | 925 | set { _throttleUpdates = value; } |
807 | } | 926 | } |
808 | public override bool IsColliding { | ||
809 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | ||
810 | set { _isColliding = value; } | ||
811 | } | ||
812 | public override bool CollidingGround { | ||
813 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | ||
814 | set { _collidingGround = value; } | ||
815 | } | ||
816 | public override bool CollidingObj { | ||
817 | get { return _collidingObj; } | ||
818 | set { _collidingObj = value; } | ||
819 | } | ||
820 | public bool IsPhantom { | 927 | public bool IsPhantom { |
821 | get { | 928 | get { |
822 | // SceneObjectPart removes phantom objects from the physics scene | 929 | // SceneObjectPart removes phantom objects from the physics scene |
@@ -831,23 +938,14 @@ public sealed class BSPrim : BSPhysObject | |||
831 | PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() | 938 | PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() |
832 | { | 939 | { |
833 | if (_floatOnWater) | 940 | if (_floatOnWater) |
834 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 941 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
835 | else | 942 | else |
836 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 943 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
837 | }); | 944 | }); |
838 | } | 945 | } |
839 | } | 946 | } |
840 | public override OMV.Vector3 RotationalVelocity { | 947 | public override OMV.Vector3 RotationalVelocity { |
841 | get { | 948 | get { |
842 | /* | ||
843 | OMV.Vector3 pv = OMV.Vector3.Zero; | ||
844 | // if close to zero, report zero | ||
845 | // This is copied from ODE but I'm not sure why it returns zero but doesn't | ||
846 | // zero the property in the physics engine. | ||
847 | if (_rotationalVelocity.ApproxEquals(pv, 0.2f)) | ||
848 | return pv; | ||
849 | */ | ||
850 | |||
851 | return _rotationalVelocity; | 949 | return _rotationalVelocity; |
852 | } | 950 | } |
853 | set { | 951 | set { |
@@ -856,7 +954,7 @@ public sealed class BSPrim : BSPhysObject | |||
856 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() | 954 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() |
857 | { | 955 | { |
858 | DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | 956 | DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); |
859 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | 957 | ForceRotationalVelocity = _rotationalVelocity; |
860 | }); | 958 | }); |
861 | } | 959 | } |
862 | } | 960 | } |
@@ -866,7 +964,11 @@ public sealed class BSPrim : BSPhysObject | |||
866 | } | 964 | } |
867 | set { | 965 | set { |
868 | _rotationalVelocity = value; | 966 | _rotationalVelocity = value; |
869 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | 967 | if (PhysBody.HasPhysicalBody) |
968 | { | ||
969 | PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | ||
970 | ActivateIfPhysical(false); | ||
971 | } | ||
870 | } | 972 | } |
871 | } | 973 | } |
872 | public override bool Kinematic { | 974 | public override bool Kinematic { |
@@ -890,9 +992,10 @@ public sealed class BSPrim : BSPhysObject | |||
890 | set { | 992 | set { |
891 | _buoyancy = value; | 993 | _buoyancy = value; |
892 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 994 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
893 | // Buoyancy is faked by changing the gravity applied to the object | 995 | // Force the recalculation of the various inertia,etc variables in the object |
894 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | 996 | DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2}", LocalID, _buoyancy, _mass); |
895 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | 997 | UpdatePhysicalMassProperties(_mass, true); |
998 | ActivateIfPhysical(false); | ||
896 | } | 999 | } |
897 | } | 1000 | } |
898 | 1001 | ||
@@ -900,17 +1003,103 @@ public sealed class BSPrim : BSPhysObject | |||
900 | public override OMV.Vector3 PIDTarget { | 1003 | public override OMV.Vector3 PIDTarget { |
901 | set { _PIDTarget = value; } | 1004 | set { _PIDTarget = value; } |
902 | } | 1005 | } |
903 | public override bool PIDActive { | ||
904 | set { _usePID = value; } | ||
905 | } | ||
906 | public override float PIDTau { | 1006 | public override float PIDTau { |
907 | set { _PIDTau = value; } | 1007 | set { _PIDTau = value; } |
908 | } | 1008 | } |
1009 | public override bool PIDActive { | ||
1010 | set { | ||
1011 | if (value) | ||
1012 | { | ||
1013 | // We're taking over after this. | ||
1014 | ZeroMotion(true); | ||
1015 | |||
1016 | _targetMotor = new BSVMotor("BSPrim.PIDTarget", | ||
1017 | _PIDTau, // timeScale | ||
1018 | BSMotor.Infinite, // decay time scale | ||
1019 | BSMotor.InfiniteVector, // friction timescale | ||
1020 | 1f // efficiency | ||
1021 | ); | ||
1022 | _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1023 | _targetMotor.SetTarget(_PIDTarget); | ||
1024 | _targetMotor.SetCurrent(RawPosition); | ||
1025 | /* | ||
1026 | _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget"); | ||
1027 | _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1028 | |||
1029 | _targetMotor.SetTarget(_PIDTarget); | ||
1030 | _targetMotor.SetCurrent(RawPosition); | ||
1031 | _targetMotor.TimeScale = _PIDTau; | ||
1032 | _targetMotor.Efficiency = 1f; | ||
1033 | */ | ||
1034 | |||
1035 | RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep) | ||
1036 | { | ||
1037 | OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below) | ||
1038 | |||
1039 | // 'movePosition' is where we'd like the prim to be at this moment. | ||
1040 | OMV.Vector3 movePosition = _targetMotor.Step(timeStep); | ||
1041 | |||
1042 | // If we are very close to our target, turn off the movement motor. | ||
1043 | if (_targetMotor.ErrorIsZero()) | ||
1044 | { | ||
1045 | DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}", | ||
1046 | LocalID, movePosition, RawPosition, Mass); | ||
1047 | ForcePosition = _targetMotor.TargetValue; | ||
1048 | _targetMotor.Enabled = false; | ||
1049 | } | ||
1050 | else | ||
1051 | { | ||
1052 | ForcePosition = movePosition; | ||
1053 | } | ||
1054 | DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition); | ||
1055 | }); | ||
1056 | } | ||
1057 | else | ||
1058 | { | ||
1059 | // Stop any targetting | ||
1060 | UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); | ||
1061 | } | ||
1062 | } | ||
1063 | } | ||
909 | 1064 | ||
910 | // Used for llSetHoverHeight and maybe vehicle height | 1065 | // Used for llSetHoverHeight and maybe vehicle height |
911 | // Hover Height will override MoveTo target's Z | 1066 | // Hover Height will override MoveTo target's Z |
912 | public override bool PIDHoverActive { | 1067 | public override bool PIDHoverActive { |
913 | set { _useHoverPID = value; } | 1068 | set { |
1069 | if (value) | ||
1070 | { | ||
1071 | // Turning the target on | ||
1072 | _hoverMotor = new BSFMotor("BSPrim.Hover", | ||
1073 | _PIDHoverTau, // timeScale | ||
1074 | BSMotor.Infinite, // decay time scale | ||
1075 | BSMotor.Infinite, // friction timescale | ||
1076 | 1f // efficiency | ||
1077 | ); | ||
1078 | _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight()); | ||
1079 | _hoverMotor.SetCurrent(RawPosition.Z); | ||
1080 | _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1081 | |||
1082 | RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep) | ||
1083 | { | ||
1084 | _hoverMotor.SetCurrent(RawPosition.Z); | ||
1085 | _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight()); | ||
1086 | float targetHeight = _hoverMotor.Step(timeStep); | ||
1087 | |||
1088 | // 'targetHeight' is where we'd like the Z of the prim to be at this moment. | ||
1089 | // Compute the amount of force to push us there. | ||
1090 | float moveForce = (targetHeight - RawPosition.Z) * Mass; | ||
1091 | // Undo anything the object thinks it's doing at the moment | ||
1092 | moveForce = -RawVelocity.Z * Mass; | ||
1093 | |||
1094 | PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce)); | ||
1095 | DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass); | ||
1096 | }); | ||
1097 | } | ||
1098 | else | ||
1099 | { | ||
1100 | UnRegisterPreStepAction("BSPrim.Hover", LocalID); | ||
1101 | } | ||
1102 | } | ||
914 | } | 1103 | } |
915 | public override float PIDHoverHeight { | 1104 | public override float PIDHoverHeight { |
916 | set { _PIDHoverHeight = value; } | 1105 | set { _PIDHoverHeight = value; } |
@@ -919,8 +1108,35 @@ public sealed class BSPrim : BSPhysObject | |||
919 | set { _PIDHoverType = value; } | 1108 | set { _PIDHoverType = value; } |
920 | } | 1109 | } |
921 | public override float PIDHoverTau { | 1110 | public override float PIDHoverTau { |
922 | set { _PIDHoverTao = value; } | 1111 | set { _PIDHoverTau = value; } |
923 | } | 1112 | } |
1113 | // Based on current position, determine what we should be hovering at now. | ||
1114 | // Must recompute often. What if we walked offa cliff> | ||
1115 | private float ComputeCurrentPIDHoverHeight() | ||
1116 | { | ||
1117 | float ret = _PIDHoverHeight; | ||
1118 | float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); | ||
1119 | |||
1120 | switch (_PIDHoverType) | ||
1121 | { | ||
1122 | case PIDHoverType.Ground: | ||
1123 | ret = groundHeight + _PIDHoverHeight; | ||
1124 | break; | ||
1125 | case PIDHoverType.GroundAndWater: | ||
1126 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); | ||
1127 | if (groundHeight > waterHeight) | ||
1128 | { | ||
1129 | ret = groundHeight + _PIDHoverHeight; | ||
1130 | } | ||
1131 | else | ||
1132 | { | ||
1133 | ret = waterHeight + _PIDHoverHeight; | ||
1134 | } | ||
1135 | break; | ||
1136 | } | ||
1137 | return ret; | ||
1138 | } | ||
1139 | |||
924 | 1140 | ||
925 | // For RotLookAt | 1141 | // For RotLookAt |
926 | public override OMV.Quaternion APIDTarget { set { return; } } | 1142 | public override OMV.Quaternion APIDTarget { set { return; } } |
@@ -928,54 +1144,45 @@ public sealed class BSPrim : BSPhysObject | |||
928 | public override float APIDStrength { set { return; } } | 1144 | public override float APIDStrength { set { return; } } |
929 | public override float APIDDamping { set { return; } } | 1145 | public override float APIDDamping { set { return; } } |
930 | 1146 | ||
931 | private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); | ||
932 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 1147 | public override void AddForce(OMV.Vector3 force, bool pushforce) { |
933 | AddForce(force, pushforce, false); | 1148 | // Since this force is being applied in only one step, make this a force per second. |
1149 | OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; | ||
1150 | AddForce(addForce, pushforce, false); | ||
934 | } | 1151 | } |
935 | // Applying a force just adds this to the total force on the object. | 1152 | // Applying a force just adds this to the total force on the object. |
1153 | // This added force will only last the next simulation tick. | ||
936 | public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | 1154 | public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
937 | // for an object, doesn't matter if force is a pushforce or not | 1155 | // for an object, doesn't matter if force is a pushforce or not |
938 | if (force.IsFinite()) | 1156 | if (!IsStatic && force.IsFinite()) |
939 | { | 1157 | { |
940 | // _force += force; | 1158 | float magnitude = force.Length(); |
941 | lock (m_accumulatedForces) | 1159 | if (magnitude > BSParam.MaxAddForceMagnitude) |
942 | m_accumulatedForces.Add(new OMV.Vector3(force)); | 1160 | { |
1161 | // Force has a limit | ||
1162 | force = force / magnitude * BSParam.MaxAddForceMagnitude; | ||
1163 | } | ||
1164 | |||
1165 | OMV.Vector3 addForce = force; | ||
1166 | // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); | ||
1167 | |||
1168 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() | ||
1169 | { | ||
1170 | // Bullet adds this central force to the total force for this tick | ||
1171 | DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); | ||
1172 | if (PhysBody.HasPhysicalBody) | ||
1173 | { | ||
1174 | PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); | ||
1175 | ActivateIfPhysical(false); | ||
1176 | } | ||
1177 | }); | ||
943 | } | 1178 | } |
944 | else | 1179 | else |
945 | { | 1180 | { |
946 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | 1181 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); |
947 | return; | 1182 | return; |
948 | } | 1183 | } |
949 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() | ||
950 | { | ||
951 | OMV.Vector3 fSum = OMV.Vector3.Zero; | ||
952 | lock (m_accumulatedForces) | ||
953 | { | ||
954 | // Sum the accumulated additional forces for one big force to apply once. | ||
955 | foreach (OMV.Vector3 v in m_accumulatedForces) | ||
956 | { | ||
957 | fSum += v; | ||
958 | } | ||
959 | m_accumulatedForces.Clear(); | ||
960 | } | ||
961 | DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); | ||
962 | if (fSum != OMV.Vector3.Zero) | ||
963 | BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); | ||
964 | }); | ||
965 | } | 1184 | } |
966 | 1185 | ||
967 | // An impulse force is scaled by the mass of the object. | ||
968 | public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime) | ||
969 | { | ||
970 | OMV.Vector3 applyImpulse = impulse; | ||
971 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate() | ||
972 | { | ||
973 | DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); | ||
974 | BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); | ||
975 | }); | ||
976 | } | ||
977 | |||
978 | private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>(); | ||
979 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 1186 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { |
980 | AddAngularForce(force, pushforce, false); | 1187 | AddAngularForce(force, pushforce, false); |
981 | } | 1188 | } |
@@ -983,42 +1190,37 @@ public sealed class BSPrim : BSPhysObject | |||
983 | { | 1190 | { |
984 | if (force.IsFinite()) | 1191 | if (force.IsFinite()) |
985 | { | 1192 | { |
986 | // _force += force; | 1193 | OMV.Vector3 angForce = force; |
987 | lock (m_accumulatedAngularForces) | 1194 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() |
988 | m_accumulatedAngularForces.Add(new OMV.Vector3(force)); | 1195 | { |
1196 | if (PhysBody.HasPhysicalBody) | ||
1197 | { | ||
1198 | PhysicsScene.PE.ApplyTorque(PhysBody, angForce); | ||
1199 | ActivateIfPhysical(false); | ||
1200 | } | ||
1201 | }); | ||
989 | } | 1202 | } |
990 | else | 1203 | else |
991 | { | 1204 | { |
992 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | 1205 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); |
993 | return; | 1206 | return; |
994 | } | 1207 | } |
995 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() | ||
996 | { | ||
997 | OMV.Vector3 fSum = OMV.Vector3.Zero; | ||
998 | lock (m_accumulatedAngularForces) | ||
999 | { | ||
1000 | // Sum the accumulated additional forces for one big force to apply once. | ||
1001 | foreach (OMV.Vector3 v in m_accumulatedAngularForces) | ||
1002 | { | ||
1003 | fSum += v; | ||
1004 | } | ||
1005 | m_accumulatedAngularForces.Clear(); | ||
1006 | } | ||
1007 | DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum); | ||
1008 | if (fSum != OMV.Vector3.Zero) | ||
1009 | { | ||
1010 | BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum); | ||
1011 | _torque = fSum; | ||
1012 | } | ||
1013 | }); | ||
1014 | } | 1208 | } |
1209 | |||
1015 | // A torque impulse. | 1210 | // A torque impulse. |
1211 | // ApplyTorqueImpulse adds torque directly to the angularVelocity. | ||
1212 | // AddAngularForce accumulates the force and applied it to the angular velocity all at once. | ||
1213 | // Computed as: angularVelocity += impulse * inertia; | ||
1016 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) | 1214 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) |
1017 | { | 1215 | { |
1018 | OMV.Vector3 applyImpulse = impulse; | 1216 | OMV.Vector3 applyImpulse = impulse; |
1019 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() | 1217 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() |
1020 | { | 1218 | { |
1021 | BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); | 1219 | if (PhysBody.HasPhysicalBody) |
1220 | { | ||
1221 | PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); | ||
1222 | ActivateIfPhysical(false); | ||
1223 | } | ||
1022 | }); | 1224 | }); |
1023 | } | 1225 | } |
1024 | 1226 | ||
@@ -1313,11 +1515,7 @@ public sealed class BSPrim : BSPhysObject | |||
1313 | } | 1515 | } |
1314 | */ | 1516 | */ |
1315 | 1517 | ||
1316 | if (returnMass <= 0) | 1518 | returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); |
1317 | returnMass = 0.0001f; | ||
1318 | |||
1319 | if (returnMass > PhysicsScene.MaximumObjectMass) | ||
1320 | returnMass = PhysicsScene.MaximumObjectMass; | ||
1321 | 1519 | ||
1322 | return returnMass; | 1520 | return returnMass; |
1323 | }// end CalculateMass | 1521 | }// end CalculateMass |
@@ -1326,7 +1524,7 @@ public sealed class BSPrim : BSPhysObject | |||
1326 | // Rebuild the geometry and object. | 1524 | // Rebuild the geometry and object. |
1327 | // This is called when the shape changes so we need to recreate the mesh/hull. | 1525 | // This is called when the shape changes so we need to recreate the mesh/hull. |
1328 | // Called at taint-time!!! | 1526 | // Called at taint-time!!! |
1329 | private void CreateGeomAndObject(bool forceRebuild) | 1527 | public void CreateGeomAndObject(bool forceRebuild) |
1330 | { | 1528 | { |
1331 | // If this prim is part of a linkset, we must remove and restore the physical | 1529 | // If this prim is part of a linkset, we must remove and restore the physical |
1332 | // links if the body is rebuilt. | 1530 | // links if the body is rebuilt. |
@@ -1336,12 +1534,11 @@ public sealed class BSPrim : BSPhysObject | |||
1336 | // Create the correct physical representation for this type of object. | 1534 | // Create the correct physical representation for this type of object. |
1337 | // Updates PhysBody and PhysShape with the new information. | 1535 | // Updates PhysBody and PhysShape with the new information. |
1338 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. | 1536 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. |
1339 | // Returns 'true' if either the body or the shape was changed. | ||
1340 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) | 1537 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) |
1341 | { | 1538 | { |
1342 | // Called if the current prim body is about to be destroyed. | 1539 | // Called if the current prim body is about to be destroyed. |
1343 | // Remove all the physical dependencies on the old body. | 1540 | // Remove all the physical dependencies on the old body. |
1344 | // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) | 1541 | // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) |
1345 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); | 1542 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); |
1346 | needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); | 1543 | needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); |
1347 | }); | 1544 | }); |
@@ -1381,54 +1578,16 @@ public sealed class BSPrim : BSPhysObject | |||
1381 | 1578 | ||
1382 | public override void UpdateProperties(EntityProperties entprop) | 1579 | public override void UpdateProperties(EntityProperties entprop) |
1383 | { | 1580 | { |
1384 | /* | 1581 | // Updates only for individual prims and for the root object of a linkset. |
1385 | UpdatedProperties changed = 0; | 1582 | if (Linkset.IsRoot(this)) |
1386 | // assign to the local variables so the normal set action does not happen | ||
1387 | // if (_position != entprop.Position) | ||
1388 | if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) | ||
1389 | { | ||
1390 | _position = entprop.Position; | ||
1391 | changed |= UpdatedProperties.Position; | ||
1392 | } | ||
1393 | // if (_orientation != entprop.Rotation) | ||
1394 | if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE)) | ||
1395 | { | ||
1396 | _orientation = entprop.Rotation; | ||
1397 | changed |= UpdatedProperties.Rotation; | ||
1398 | } | ||
1399 | // if (_velocity != entprop.Velocity) | ||
1400 | if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE)) | ||
1401 | { | ||
1402 | _velocity = entprop.Velocity; | ||
1403 | changed |= UpdatedProperties.Velocity; | ||
1404 | } | ||
1405 | // if (_acceleration != entprop.Acceleration) | ||
1406 | if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE)) | ||
1407 | { | ||
1408 | _acceleration = entprop.Acceleration; | ||
1409 | changed |= UpdatedProperties.Acceleration; | ||
1410 | } | ||
1411 | // if (_rotationalVelocity != entprop.RotationalVelocity) | ||
1412 | if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE)) | ||
1413 | { | ||
1414 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1415 | changed |= UpdatedProperties.RotationalVel; | ||
1416 | } | ||
1417 | if (changed != 0) | ||
1418 | { | 1583 | { |
1419 | // Only update the position of single objects and linkset roots | 1584 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet |
1420 | if (Linkset.IsRoot(this)) | 1585 | // TODO: handle physics introduced by Bullet with computed vehicle physics. |
1586 | if (_vehicle.IsActive) | ||
1421 | { | 1587 | { |
1422 | base.RequestPhysicsterseUpdate(); | 1588 | entprop.RotationalVelocity = OMV.Vector3.Zero; |
1423 | } | 1589 | } |
1424 | } | ||
1425 | */ | ||
1426 | |||
1427 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. | ||
1428 | 1590 | ||
1429 | // Updates only for individual prims and for the root object of a linkset. | ||
1430 | if (Linkset.IsRoot(this)) | ||
1431 | { | ||
1432 | // Assign directly to the local variables so the normal set action does not happen | 1591 | // Assign directly to the local variables so the normal set action does not happen |
1433 | _position = entprop.Position; | 1592 | _position = entprop.Position; |
1434 | _orientation = entprop.Rotation; | 1593 | _orientation = entprop.Rotation; |
@@ -1437,21 +1596,19 @@ public sealed class BSPrim : BSPhysObject | |||
1437 | _rotationalVelocity = entprop.RotationalVelocity; | 1596 | _rotationalVelocity = entprop.RotationalVelocity; |
1438 | 1597 | ||
1439 | // The sanity check can change the velocity and/or position. | 1598 | // The sanity check can change the velocity and/or position. |
1440 | if (PositionSanityCheck(true)) | 1599 | if (IsPhysical && PositionSanityCheck(true)) |
1441 | { | 1600 | { |
1442 | entprop.Position = _position; | 1601 | entprop.Position = _position; |
1443 | entprop.Velocity = _velocity; | 1602 | entprop.Velocity = _velocity; |
1444 | } | 1603 | } |
1445 | 1604 | ||
1446 | // remember the current and last set values | 1605 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG |
1447 | LastEntityProperties = CurrentEntityProperties; | ||
1448 | CurrentEntityProperties = entprop; | ||
1449 | |||
1450 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; | ||
1451 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", | 1606 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", |
1452 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); | 1607 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); |
1453 | 1608 | ||
1454 | // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG | 1609 | // remember the current and last set values |
1610 | LastEntityProperties = CurrentEntityProperties; | ||
1611 | CurrentEntityProperties = entprop; | ||
1455 | 1612 | ||
1456 | base.RequestPhysicsterseUpdate(); | 1613 | base.RequestPhysicsterseUpdate(); |
1457 | } | 1614 | } |
@@ -1466,7 +1623,7 @@ public sealed class BSPrim : BSPhysObject | |||
1466 | */ | 1623 | */ |
1467 | 1624 | ||
1468 | // The linkset implimentation might want to know about this. | 1625 | // The linkset implimentation might want to know about this. |
1469 | Linkset.UpdateProperties(this); | 1626 | Linkset.UpdateProperties(this, true); |
1470 | } | 1627 | } |
1471 | } | 1628 | } |
1472 | } | 1629 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 27a78d1..7017194 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | using System; | 27 | using System; |
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Reflection; | ||
29 | using System.Runtime.InteropServices; | 30 | using System.Runtime.InteropServices; |
30 | using System.Text; | 31 | using System.Text; |
31 | using System.Threading; | 32 | using System.Threading; |
@@ -38,40 +39,22 @@ using Nini.Config; | |||
38 | using log4net; | 39 | using log4net; |
39 | using OpenMetaverse; | 40 | using OpenMetaverse; |
40 | 41 | ||
41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) | ||
42 | // Test sculpties (verified that they don't work) | ||
43 | // Compute physics FPS reasonably | ||
44 | // Based on material, set density and friction | ||
45 | // Don't use constraints in linksets of non-physical objects. Means having to move children manually. | ||
46 | // Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? | ||
47 | // In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) | ||
48 | // At the moment, physical and phantom causes object to drop through the terrain | ||
49 | // Physical phantom objects and related typing (collision options ) | ||
50 | // Check out llVolumeDetect. Must do something for that. | ||
51 | // Use collision masks for collision with terrain and phantom objects | ||
52 | // More efficient memory usage when passing hull information from BSPrim to BulletSim | ||
53 | // Should prim.link() and prim.delink() membership checking happen at taint time? | ||
54 | // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once. | ||
55 | // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect | ||
56 | // Implement LockAngularMotion | ||
57 | // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) | ||
58 | // Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. | ||
59 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? | ||
60 | // Check terrain size. 128 or 127? | ||
61 | // Raycast | ||
62 | // | ||
63 | namespace OpenSim.Region.Physics.BulletSPlugin | 42 | namespace OpenSim.Region.Physics.BulletSPlugin |
64 | { | 43 | { |
65 | public sealed class BSScene : PhysicsScene, IPhysicsParameters | 44 | public sealed class BSScene : PhysicsScene, IPhysicsParameters |
66 | { | 45 | { |
67 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | 46 | internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); |
68 | private static readonly string LogHeader = "[BULLETS SCENE]"; | 47 | internal static readonly string LogHeader = "[BULLETS SCENE]"; |
69 | 48 | ||
70 | // The name of the region we're working for. | 49 | // The name of the region we're working for. |
71 | public string RegionName { get; private set; } | 50 | public string RegionName { get; private set; } |
72 | 51 | ||
73 | public string BulletSimVersion = "?"; | 52 | public string BulletSimVersion = "?"; |
74 | 53 | ||
54 | // The handle to the underlying managed or unmanaged version of Bullet being used. | ||
55 | public string BulletEngineName { get; private set; } | ||
56 | public BSAPITemplate PE; | ||
57 | |||
75 | public Dictionary<uint, BSPhysObject> PhysObjects; | 58 | public Dictionary<uint, BSPhysObject> PhysObjects; |
76 | public BSShapeCollection Shapes; | 59 | public BSShapeCollection Shapes; |
77 | 60 | ||
@@ -82,32 +65,30 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
82 | // every tick so OpenSim will update its animation. | 65 | // every tick so OpenSim will update its animation. |
83 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); | 66 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); |
84 | 67 | ||
85 | // List of all the objects that have vehicle properties and should be called | ||
86 | // to update each physics step. | ||
87 | private List<BSPhysObject> m_vehicles = new List<BSPhysObject>(); | ||
88 | |||
89 | // let my minuions use my logger | 68 | // let my minuions use my logger |
90 | public ILog Logger { get { return m_log; } } | 69 | public ILog Logger { get { return m_log; } } |
91 | 70 | ||
92 | public IMesher mesher; | 71 | public IMesher mesher; |
93 | // Level of Detail values kept as float because that's what the Meshmerizer wants | ||
94 | public float MeshLOD { get; private set; } | ||
95 | public float MeshMegaPrimLOD { get; private set; } | ||
96 | public float MeshMegaPrimThreshold { get; private set; } | ||
97 | public float SculptLOD { get; private set; } | ||
98 | |||
99 | public uint WorldID { get; private set; } | 72 | public uint WorldID { get; private set; } |
100 | public BulletSim World { get; private set; } | 73 | public BulletWorld World { get; private set; } |
101 | 74 | ||
102 | // All the constraints that have been allocated in this instance. | 75 | // All the constraints that have been allocated in this instance. |
103 | public BSConstraintCollection Constraints { get; private set; } | 76 | public BSConstraintCollection Constraints { get; private set; } |
104 | 77 | ||
105 | // Simulation parameters | 78 | // Simulation parameters |
106 | private int m_maxSubSteps; | 79 | internal int m_maxSubSteps; |
107 | private float m_fixedTimeStep; | 80 | internal float m_fixedTimeStep; |
108 | private long m_simulationStep = 0; | 81 | internal long m_simulationStep = 0; |
82 | internal float NominalFrameRate { get; set; } | ||
109 | public long SimulationStep { get { return m_simulationStep; } } | 83 | public long SimulationStep { get { return m_simulationStep; } } |
110 | private int m_taintsToProcessPerStep; | 84 | internal int m_taintsToProcessPerStep; |
85 | internal float LastTimeStep { get; private set; } | ||
86 | |||
87 | // Physical objects can register for prestep or poststep events | ||
88 | public delegate void PreStepAction(float timeStep); | ||
89 | public delegate void PostStepAction(float timeStep); | ||
90 | public event PreStepAction BeforeStep; | ||
91 | public event PreStepAction AfterStep; | ||
111 | 92 | ||
112 | // A value of the time now so all the collision and update routines do not have to get their own | 93 | // A value of the time now so all the collision and update routines do not have to get their own |
113 | // Set to 'now' just before all the prims and actors are called for collisions and updates | 94 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
@@ -121,31 +102,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
121 | public bool InTaintTime { get; private set; } | 102 | public bool InTaintTime { get; private set; } |
122 | 103 | ||
123 | // Pinned memory used to pass step information between managed and unmanaged | 104 | // Pinned memory used to pass step information between managed and unmanaged |
124 | private int m_maxCollisionsPerFrame; | 105 | internal int m_maxCollisionsPerFrame; |
125 | private CollisionDesc[] m_collisionArray; | 106 | internal CollisionDesc[] m_collisionArray; |
126 | private GCHandle m_collisionArrayPinnedHandle; | ||
127 | 107 | ||
128 | private int m_maxUpdatesPerFrame; | 108 | internal int m_maxUpdatesPerFrame; |
129 | private EntityProperties[] m_updateArray; | 109 | internal EntityProperties[] m_updateArray; |
130 | private GCHandle m_updateArrayPinnedHandle; | ||
131 | |||
132 | public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed | ||
133 | public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes | ||
134 | public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects | ||
135 | |||
136 | public float PID_D { get; private set; } // derivative | ||
137 | public float PID_P { get; private set; } // proportional | ||
138 | 110 | ||
139 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero | 111 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero |
140 | public const uint GROUNDPLANE_ID = 1; | 112 | public const uint GROUNDPLANE_ID = 1; |
141 | public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here | 113 | public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here |
142 | 114 | ||
143 | private float m_waterLevel; | 115 | public float SimpleWaterLevel { get; set; } |
144 | public BSTerrainManager TerrainManager { get; private set; } | 116 | public BSTerrainManager TerrainManager { get; private set; } |
145 | 117 | ||
146 | public ConfigurationParameters Params | 118 | public ConfigurationParameters Params |
147 | { | 119 | { |
148 | get { return m_params[0]; } | 120 | get { return UnmanagedParams[0]; } |
149 | } | 121 | } |
150 | public Vector3 DefaultGravity | 122 | public Vector3 DefaultGravity |
151 | { | 123 | { |
@@ -157,8 +129,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
157 | get { return Params.gravity; } | 129 | get { return Params.gravity; } |
158 | } | 130 | } |
159 | 131 | ||
160 | public float MaximumObjectMass { get; private set; } | ||
161 | |||
162 | // When functions in the unmanaged code must be called, it is only | 132 | // When functions in the unmanaged code must be called, it is only |
163 | // done at a known time just before the simulation step. The taint | 133 | // done at a known time just before the simulation step. The taint |
164 | // system saves all these function calls and executes them in | 134 | // system saves all these function calls and executes them in |
@@ -181,13 +151,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
181 | 151 | ||
182 | // A pointer to an instance if this structure is passed to the C++ code | 152 | // A pointer to an instance if this structure is passed to the C++ code |
183 | // Used to pass basic configuration values to the unmanaged code. | 153 | // Used to pass basic configuration values to the unmanaged code. |
184 | ConfigurationParameters[] m_params; | 154 | internal ConfigurationParameters[] UnmanagedParams; |
185 | GCHandle m_paramsHandle; | ||
186 | |||
187 | // Handle to the callback used by the unmanaged code to call into the managed code. | ||
188 | // Used for debug logging. | ||
189 | // Need to store the handle in a persistant variable so it won't be freed. | ||
190 | private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; | ||
191 | 155 | ||
192 | // Sometimes you just have to log everything. | 156 | // Sometimes you just have to log everything. |
193 | public Logging.LogWriter PhysicsLogging; | 157 | public Logging.LogWriter PhysicsLogging; |
@@ -195,8 +159,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
195 | private string m_physicsLoggingDir; | 159 | private string m_physicsLoggingDir; |
196 | private string m_physicsLoggingPrefix; | 160 | private string m_physicsLoggingPrefix; |
197 | private int m_physicsLoggingFileMinutes; | 161 | private int m_physicsLoggingFileMinutes; |
162 | private bool m_physicsLoggingDoFlush; | ||
163 | private bool m_physicsPhysicalDumpEnabled; | ||
164 | public float PhysicsMetricDumpFrames { get; set; } | ||
198 | // 'true' of the vehicle code is to log lots of details | 165 | // 'true' of the vehicle code is to log lots of details |
199 | public bool VehicleLoggingEnabled { get; private set; } | 166 | public bool VehicleLoggingEnabled { get; private set; } |
167 | public bool VehiclePhysicalLoggingEnabled { get; private set; } | ||
200 | 168 | ||
201 | #region Construction and Initialization | 169 | #region Construction and Initialization |
202 | public BSScene(string identifier) | 170 | public BSScene(string identifier) |
@@ -216,17 +184,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
216 | Shapes = new BSShapeCollection(this); | 184 | Shapes = new BSShapeCollection(this); |
217 | 185 | ||
218 | // Allocate pinned memory to pass parameters. | 186 | // Allocate pinned memory to pass parameters. |
219 | m_params = new ConfigurationParameters[1]; | 187 | UnmanagedParams = new ConfigurationParameters[1]; |
220 | m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); | ||
221 | 188 | ||
222 | // Set default values for physics parameters plus any overrides from the ini file | 189 | // Set default values for physics parameters plus any overrides from the ini file |
223 | GetInitialParameterValues(config); | 190 | GetInitialParameterValues(config); |
224 | 191 | ||
225 | // allocate more pinned memory close to the above in an attempt to get the memory all together | 192 | // Get the connection to the physics engine (could be native or one of many DLLs) |
226 | m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; | 193 | PE = SelectUnderlyingBulletEngine(BulletEngineName); |
227 | m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned); | ||
228 | m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; | ||
229 | m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); | ||
230 | 194 | ||
231 | // Enable very detailed logging. | 195 | // Enable very detailed logging. |
232 | // By creating an empty logger when not logging, the log message invocation code | 196 | // By creating an empty logger when not logging, the log message invocation code |
@@ -234,28 +198,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
234 | if (m_physicsLoggingEnabled) | 198 | if (m_physicsLoggingEnabled) |
235 | { | 199 | { |
236 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); | 200 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); |
201 | PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages. | ||
237 | } | 202 | } |
238 | else | 203 | else |
239 | { | 204 | { |
240 | PhysicsLogging = new Logging.LogWriter(); | 205 | PhysicsLogging = new Logging.LogWriter(); |
241 | } | 206 | } |
242 | 207 | ||
243 | // If Debug logging level, enable logging from the unmanaged code | 208 | // Allocate memory for returning of the updates and collisions from the physics engine |
244 | m_DebugLogCallbackHandle = null; | 209 | m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; |
245 | if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) | 210 | m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; |
246 | { | ||
247 | m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); | ||
248 | if (PhysicsLogging.Enabled) | ||
249 | // The handle is saved in a variable to make sure it doesn't get freed after this call | ||
250 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); | ||
251 | else | ||
252 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); | ||
253 | } | ||
254 | |||
255 | // Get the version of the DLL | ||
256 | // TODO: this doesn't work yet. Something wrong with marshaling the returned string. | ||
257 | // BulletSimVersion = BulletSimAPI.GetVersion(); | ||
258 | // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); | ||
259 | 211 | ||
260 | // The bounding box for the simulated world. The origin is 0,0,0 unless we're | 212 | // The bounding box for the simulated world. The origin is 0,0,0 unless we're |
261 | // a child in a mega-region. | 213 | // a child in a mega-region. |
@@ -263,18 +215,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
263 | // area. It tracks active objects no matter where they are. | 215 | // area. It tracks active objects no matter where they are. |
264 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | 216 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); |
265 | 217 | ||
266 | // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); | 218 | World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray); |
267 | World = new BulletSim(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(), | ||
268 | m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), | ||
269 | m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(), | ||
270 | m_DebugLogCallbackHandle)); | ||
271 | 219 | ||
272 | Constraints = new BSConstraintCollection(World); | 220 | Constraints = new BSConstraintCollection(World); |
273 | 221 | ||
274 | TerrainManager = new BSTerrainManager(this); | 222 | TerrainManager = new BSTerrainManager(this); |
275 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); | 223 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); |
276 | 224 | ||
277 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation); | 225 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); |
278 | 226 | ||
279 | InTaintTime = false; | 227 | InTaintTime = false; |
280 | m_initialized = true; | 228 | m_initialized = true; |
@@ -285,9 +233,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
285 | private void GetInitialParameterValues(IConfigSource config) | 233 | private void GetInitialParameterValues(IConfigSource config) |
286 | { | 234 | { |
287 | ConfigurationParameters parms = new ConfigurationParameters(); | 235 | ConfigurationParameters parms = new ConfigurationParameters(); |
288 | m_params[0] = parms; | 236 | UnmanagedParams[0] = parms; |
289 | 237 | ||
290 | SetParameterDefaultValues(); | 238 | BSParam.SetParameterDefaultValues(this); |
291 | 239 | ||
292 | if (config != null) | 240 | if (config != null) |
293 | { | 241 | { |
@@ -295,19 +243,34 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
295 | IConfig pConfig = config.Configs["BulletSim"]; | 243 | IConfig pConfig = config.Configs["BulletSim"]; |
296 | if (pConfig != null) | 244 | if (pConfig != null) |
297 | { | 245 | { |
298 | SetParameterConfigurationValues(pConfig); | 246 | BSParam.SetParameterConfigurationValues(this, pConfig); |
247 | |||
248 | // There are two Bullet implementations to choose from | ||
249 | BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged"); | ||
299 | 250 | ||
300 | // Very detailed logging for physics debugging | 251 | // Very detailed logging for physics debugging |
252 | // TODO: the boolean values can be moved to the normal parameter processing. | ||
301 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); | 253 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); |
302 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); | 254 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); |
303 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); | 255 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); |
304 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); | 256 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); |
257 | m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false); | ||
258 | m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false); | ||
305 | // Very detailed logging for vehicle debugging | 259 | // Very detailed logging for vehicle debugging |
306 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); | 260 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); |
261 | VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false); | ||
307 | 262 | ||
308 | // Do any replacements in the parameters | 263 | // Do any replacements in the parameters |
309 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); | 264 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); |
310 | } | 265 | } |
266 | |||
267 | // The material characteristics. | ||
268 | BSMaterials.InitializeFromDefaults(Params); | ||
269 | if (pConfig != null) | ||
270 | { | ||
271 | // Let the user add new and interesting material property values. | ||
272 | BSMaterials.InitializefromParameters(pConfig); | ||
273 | } | ||
311 | } | 274 | } |
312 | } | 275 | } |
313 | 276 | ||
@@ -326,16 +289,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
326 | return ret; | 289 | return ret; |
327 | } | 290 | } |
328 | 291 | ||
329 | // Called directly from unmanaged code so don't do much | 292 | // Select the connection to the actual Bullet implementation. |
330 | private void BulletLogger(string msg) | 293 | // The main engine selection is the engineName up to the first hypen. |
294 | // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name | ||
295 | // is passed to the engine to do its special selection, etc. | ||
296 | private BSAPITemplate SelectUnderlyingBulletEngine(string engineName) | ||
331 | { | 297 | { |
332 | m_log.Debug("[BULLETS UNMANAGED]:" + msg); | 298 | // For the moment, do a simple switch statement. |
333 | } | 299 | // Someday do fancyness with looking up the interfaces in the assembly. |
300 | BSAPITemplate ret = null; | ||
334 | 301 | ||
335 | // Called directly from unmanaged code so don't do much | 302 | string selectionName = engineName.ToLower(); |
336 | private void BulletLoggerPhysLog(string msg) | 303 | int hyphenIndex = engineName.IndexOf("-"); |
337 | { | 304 | if (hyphenIndex > 0) |
338 | DetailLog("[BULLETS UNMANAGED]:" + msg); | 305 | selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1); |
306 | |||
307 | switch (selectionName) | ||
308 | { | ||
309 | case "bulletunmanaged": | ||
310 | ret = new BSAPIUnman(engineName, this); | ||
311 | break; | ||
312 | case "bulletxna": | ||
313 | ret = new BSAPIXNA(engineName, this); | ||
314 | break; | ||
315 | } | ||
316 | |||
317 | if (ret == null) | ||
318 | { | ||
319 | m_log.ErrorFormat("{0) COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader); | ||
320 | } | ||
321 | else | ||
322 | { | ||
323 | m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); | ||
324 | } | ||
325 | |||
326 | return ret; | ||
339 | } | 327 | } |
340 | 328 | ||
341 | public override void Dispose() | 329 | public override void Dispose() |
@@ -345,8 +333,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
345 | // make sure no stepping happens while we're deleting stuff | 333 | // make sure no stepping happens while we're deleting stuff |
346 | m_initialized = false; | 334 | m_initialized = false; |
347 | 335 | ||
348 | TerrainManager.ReleaseGroundPlaneAndTerrain(); | ||
349 | |||
350 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) | 336 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) |
351 | { | 337 | { |
352 | kvp.Value.Destroy(); | 338 | kvp.Value.Destroy(); |
@@ -366,8 +352,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
366 | Shapes = null; | 352 | Shapes = null; |
367 | } | 353 | } |
368 | 354 | ||
355 | if (TerrainManager != null) | ||
356 | { | ||
357 | TerrainManager.ReleaseGroundPlaneAndTerrain(); | ||
358 | TerrainManager.Dispose(); | ||
359 | TerrainManager = null; | ||
360 | } | ||
361 | |||
369 | // Anything left in the unmanaged code should be cleaned out | 362 | // Anything left in the unmanaged code should be cleaned out |
370 | BulletSimAPI.Shutdown2(World.ptr); | 363 | PE.Shutdown(World); |
371 | 364 | ||
372 | // Not logging any more | 365 | // Not logging any more |
373 | PhysicsLogging.Close(); | 366 | PhysicsLogging.Close(); |
@@ -474,41 +467,55 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
474 | // Simulate one timestep | 467 | // Simulate one timestep |
475 | public override float Simulate(float timeStep) | 468 | public override float Simulate(float timeStep) |
476 | { | 469 | { |
470 | // prevent simulation until we've been initialized | ||
471 | if (!m_initialized) return 5.0f; | ||
472 | |||
473 | LastTimeStep = timeStep; | ||
474 | |||
477 | int updatedEntityCount = 0; | 475 | int updatedEntityCount = 0; |
478 | IntPtr updatedEntitiesPtr; | ||
479 | int collidersCount = 0; | 476 | int collidersCount = 0; |
480 | IntPtr collidersPtr; | ||
481 | 477 | ||
482 | int beforeTime = 0; | 478 | int beforeTime = 0; |
483 | int simTime = 0; | 479 | int simTime = 0; |
484 | 480 | ||
485 | // prevent simulation until we've been initialized | ||
486 | if (!m_initialized) return 5.0f; | ||
487 | |||
488 | // update the prim states while we know the physics engine is not busy | 481 | // update the prim states while we know the physics engine is not busy |
489 | int numTaints = _taintOperations.Count; | 482 | int numTaints = _taintOperations.Count; |
483 | |||
484 | InTaintTime = true; // Only used for debugging so locking is not necessary. | ||
485 | |||
486 | ProcessTaints(); | ||
487 | |||
488 | // Some of the physical objects requre individual, pre-step calls | ||
489 | TriggerPreStepEvent(timeStep); | ||
490 | |||
491 | // the prestep actions might have added taints | ||
492 | numTaints += _taintOperations.Count; | ||
490 | ProcessTaints(); | 493 | ProcessTaints(); |
491 | 494 | ||
492 | // Some of the prims operate with special vehicle properties | 495 | InTaintTime = false; // Only used for debugging so locking is not necessary. |
493 | ProcessVehicles(timeStep); | 496 | |
494 | ProcessTaints(); // the vehicles might have added taints | 497 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. |
498 | // Only enable this in a limited test world with few objects. | ||
499 | if (m_physicsPhysicalDumpEnabled) | ||
500 | PE.DumpAllInfo(World); | ||
495 | 501 | ||
496 | // step the physical world one interval | 502 | // step the physical world one interval |
497 | m_simulationStep++; | 503 | m_simulationStep++; |
498 | int numSubSteps = 0; | 504 | int numSubSteps = 0; |
499 | |||
500 | try | 505 | try |
501 | { | 506 | { |
502 | if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG | 507 | if (PhysicsLogging.Enabled) |
503 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | 508 | beforeTime = Util.EnvironmentTickCount(); |
504 | 509 | ||
505 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, | 510 | numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); |
506 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); | ||
507 | 511 | ||
508 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); | 512 | if (PhysicsLogging.Enabled) |
509 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", | 513 | { |
510 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); | 514 | simTime = Util.EnvironmentTickCountSubtract(beforeTime); |
511 | if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG | 515 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", |
516 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | ||
517 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | ||
518 | } | ||
512 | } | 519 | } |
513 | catch (Exception e) | 520 | catch (Exception e) |
514 | { | 521 | { |
@@ -520,9 +527,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
520 | collidersCount = 0; | 527 | collidersCount = 0; |
521 | } | 528 | } |
522 | 529 | ||
523 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in | 530 | if ((m_simulationStep % PhysicsMetricDumpFrames) == 0) |
531 | PE.DumpPhysicsStatistics(World); | ||
524 | 532 | ||
525 | // Get a value for 'now' so all the collision and update routines don't have to get their own | 533 | // Get a value for 'now' so all the collision and update routines don't have to get their own. |
526 | SimulationNowTime = Util.EnvironmentTickCount(); | 534 | SimulationNowTime = Util.EnvironmentTickCount(); |
527 | 535 | ||
528 | // If there were collisions, process them by sending the event to the prim. | 536 | // If there were collisions, process them by sending the event to the prim. |
@@ -562,12 +570,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
562 | 570 | ||
563 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | 571 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. |
564 | // Not done above because it is inside an iteration of ObjectWithCollisions. | 572 | // Not done above because it is inside an iteration of ObjectWithCollisions. |
573 | // This complex collision processing is required to create an empty collision | ||
574 | // event call after all real collisions have happened on an object. This enables | ||
575 | // the simulator to generate the 'collision end' event. | ||
565 | if (ObjectsWithNoMoreCollisions.Count > 0) | 576 | if (ObjectsWithNoMoreCollisions.Count > 0) |
566 | { | 577 | { |
567 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | 578 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) |
568 | ObjectsWithCollisions.Remove(po); | 579 | ObjectsWithCollisions.Remove(po); |
569 | ObjectsWithNoMoreCollisions.Clear(); | 580 | ObjectsWithNoMoreCollisions.Clear(); |
570 | } | 581 | } |
582 | // Done with collisions. | ||
571 | 583 | ||
572 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine | 584 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine |
573 | if (updatedEntityCount > 0) | 585 | if (updatedEntityCount > 0) |
@@ -583,17 +595,17 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
583 | } | 595 | } |
584 | } | 596 | } |
585 | 597 | ||
586 | ProcessPostStepTaints(); | 598 | TriggerPostStepEvent(timeStep); |
587 | 599 | ||
588 | // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 600 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. |
589 | // Only enable this in a limited test world with few objects. | 601 | // Only enable this in a limited test world with few objects. |
590 | // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG | 602 | if (m_physicsPhysicalDumpEnabled) |
603 | PE.DumpAllInfo(World); | ||
591 | 604 | ||
592 | // The physics engine returns the number of milliseconds it simulated this call. | 605 | // The physics engine returns the number of milliseconds it simulated this call. |
593 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | 606 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. |
594 | // We multiply by 55 to give a recognizable running rate (55 or less). | 607 | // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). |
595 | return numSubSteps * m_fixedTimeStep * 1000 * 55; | 608 | return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; |
596 | // return timeStep * 1000 * 55; | ||
597 | } | 609 | } |
598 | 610 | ||
599 | // Something has collided | 611 | // Something has collided |
@@ -639,12 +651,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
639 | 651 | ||
640 | public override void SetWaterLevel(float baseheight) | 652 | public override void SetWaterLevel(float baseheight) |
641 | { | 653 | { |
642 | m_waterLevel = baseheight; | 654 | SimpleWaterLevel = baseheight; |
643 | } | ||
644 | // Someday.... | ||
645 | public float GetWaterLevelAtXYZ(Vector3 loc) | ||
646 | { | ||
647 | return m_waterLevel; | ||
648 | } | 655 | } |
649 | 656 | ||
650 | public override void DeleteTerrain() | 657 | public override void DeleteTerrain() |
@@ -681,6 +688,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
681 | public override bool IsThreaded { get { return false; } } | 688 | public override bool IsThreaded { get { return false; } } |
682 | 689 | ||
683 | #region Taints | 690 | #region Taints |
691 | // The simulation execution order is: | ||
692 | // Simulate() | ||
693 | // DoOneTimeTaints | ||
694 | // TriggerPreStepEvent | ||
695 | // DoOneTimeTaints | ||
696 | // Step() | ||
697 | // ProcessAndForwardCollisions | ||
698 | // ProcessAndForwardPropertyUpdates | ||
699 | // TriggerPostStepEvent | ||
684 | 700 | ||
685 | // Calls to the PhysicsActors can't directly call into the physics engine | 701 | // Calls to the PhysicsActors can't directly call into the physics engine |
686 | // because it might be busy. We delay changes to a known time. | 702 | // because it might be busy. We delay changes to a known time. |
@@ -707,58 +723,35 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
707 | TaintedObject(ident, callback); | 723 | TaintedObject(ident, callback); |
708 | } | 724 | } |
709 | 725 | ||
726 | private void TriggerPreStepEvent(float timeStep) | ||
727 | { | ||
728 | PreStepAction actions = BeforeStep; | ||
729 | if (actions != null) | ||
730 | actions(timeStep); | ||
731 | |||
732 | } | ||
733 | |||
734 | private void TriggerPostStepEvent(float timeStep) | ||
735 | { | ||
736 | PreStepAction actions = AfterStep; | ||
737 | if (actions != null) | ||
738 | actions(timeStep); | ||
739 | |||
740 | } | ||
741 | |||
710 | // When someone tries to change a property on a BSPrim or BSCharacter, the object queues | 742 | // When someone tries to change a property on a BSPrim or BSCharacter, the object queues |
711 | // a callback into itself to do the actual property change. That callback is called | 743 | // a callback into itself to do the actual property change. That callback is called |
712 | // here just before the physics engine is called to step the simulation. | 744 | // here just before the physics engine is called to step the simulation. |
713 | public void ProcessTaints() | 745 | public void ProcessTaints() |
714 | { | 746 | { |
715 | InTaintTime = true; // Only used for debugging so locking is not necessary. | ||
716 | ProcessRegularTaints(); | 747 | ProcessRegularTaints(); |
717 | ProcessPostTaintTaints(); | 748 | ProcessPostTaintTaints(); |
718 | InTaintTime = false; | ||
719 | } | 749 | } |
720 | 750 | ||
721 | private void ProcessRegularTaints() | 751 | private void ProcessRegularTaints() |
722 | { | 752 | { |
723 | if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process | 753 | if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process |
724 | { | 754 | { |
725 | /* | ||
726 | // Code to limit the number of taints processed per step. Meant to limit step time. | ||
727 | // Unsure if a good idea as code assumes that taints are done before the step. | ||
728 | int taintCount = m_taintsToProcessPerStep; | ||
729 | TaintCallbackEntry oneCallback = new TaintCallbackEntry(); | ||
730 | while (_taintOperations.Count > 0 && taintCount-- > 0) | ||
731 | { | ||
732 | bool gotOne = false; | ||
733 | lock (_taintLock) | ||
734 | { | ||
735 | if (_taintOperations.Count > 0) | ||
736 | { | ||
737 | oneCallback = _taintOperations[0]; | ||
738 | _taintOperations.RemoveAt(0); | ||
739 | gotOne = true; | ||
740 | } | ||
741 | } | ||
742 | if (gotOne) | ||
743 | { | ||
744 | try | ||
745 | { | ||
746 | DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); | ||
747 | oneCallback.callback(); | ||
748 | } | ||
749 | catch (Exception e) | ||
750 | { | ||
751 | DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG | ||
752 | m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e); | ||
753 | } | ||
754 | } | ||
755 | } | ||
756 | if (_taintOperations.Count > 0) | ||
757 | { | ||
758 | DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count); | ||
759 | } | ||
760 | */ | ||
761 | |||
762 | // swizzle a new list into the list location so we can process what's there | 755 | // swizzle a new list into the list location so we can process what's there |
763 | List<TaintCallbackEntry> oldList; | 756 | List<TaintCallbackEntry> oldList; |
764 | lock (_taintLock) | 757 | lock (_taintLock) |
@@ -797,6 +790,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
797 | return; | 790 | return; |
798 | } | 791 | } |
799 | 792 | ||
793 | // Taints that happen after the normal taint processing but before the simulation step. | ||
800 | private void ProcessPostTaintTaints() | 794 | private void ProcessPostTaintTaints() |
801 | { | 795 | { |
802 | if (_postTaintOperations.Count > 0) | 796 | if (_postTaintOperations.Count > 0) |
@@ -824,45 +818,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
824 | } | 818 | } |
825 | } | 819 | } |
826 | 820 | ||
827 | public void PostStepTaintObject(String ident, TaintCallback callback) | ||
828 | { | ||
829 | if (!m_initialized) return; | ||
830 | |||
831 | lock (_taintLock) | ||
832 | { | ||
833 | _postStepOperations.Add(new TaintCallbackEntry(ident, callback)); | ||
834 | } | ||
835 | |||
836 | return; | ||
837 | } | ||
838 | |||
839 | private void ProcessPostStepTaints() | ||
840 | { | ||
841 | if (_postStepOperations.Count > 0) | ||
842 | { | ||
843 | List<TaintCallbackEntry> oldList; | ||
844 | lock (_taintLock) | ||
845 | { | ||
846 | oldList = _postStepOperations; | ||
847 | _postStepOperations = new List<TaintCallbackEntry>(); | ||
848 | } | ||
849 | |||
850 | foreach (TaintCallbackEntry tcbe in oldList) | ||
851 | { | ||
852 | try | ||
853 | { | ||
854 | DetailLog("{0},BSScene.ProcessPostStepTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG | ||
855 | tcbe.callback(); | ||
856 | } | ||
857 | catch (Exception e) | ||
858 | { | ||
859 | m_log.ErrorFormat("{0}: ProcessPostStepTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); | ||
860 | } | ||
861 | } | ||
862 | oldList.Clear(); | ||
863 | } | ||
864 | } | ||
865 | |||
866 | // Only used for debugging. Does not change state of anything so locking is not necessary. | 821 | // Only used for debugging. Does not change state of anything so locking is not necessary. |
867 | public bool AssertInTaintTime(string whereFrom) | 822 | public bool AssertInTaintTime(string whereFrom) |
868 | { | 823 | { |
@@ -870,517 +825,21 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
870 | { | 825 | { |
871 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); | 826 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); |
872 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); | 827 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); |
873 | Util.PrintCallStack(); // Prints the stack into the DEBUG log file. | 828 | Util.PrintCallStack(DetailLog); |
874 | } | 829 | } |
875 | return InTaintTime; | 830 | return InTaintTime; |
876 | } | 831 | } |
877 | 832 | ||
878 | #endregion // Taints | 833 | #endregion // Taints |
879 | 834 | ||
880 | #region Vehicles | ||
881 | |||
882 | public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) | ||
883 | { | ||
884 | RemoveVehiclePrim(vehic); | ||
885 | if (newType != Vehicle.TYPE_NONE) | ||
886 | { | ||
887 | // make it so the scene will call us each tick to do vehicle things | ||
888 | AddVehiclePrim(vehic); | ||
889 | } | ||
890 | } | ||
891 | |||
892 | // Make so the scene will call this prim for vehicle actions each tick. | ||
893 | // Safe to call if prim is already in the vehicle list. | ||
894 | public void AddVehiclePrim(BSPrim vehicle) | ||
895 | { | ||
896 | lock (m_vehicles) | ||
897 | { | ||
898 | if (!m_vehicles.Contains(vehicle)) | ||
899 | { | ||
900 | m_vehicles.Add(vehicle); | ||
901 | } | ||
902 | } | ||
903 | } | ||
904 | |||
905 | // Remove a prim from our list of vehicles. | ||
906 | // Safe to call if the prim is not in the vehicle list. | ||
907 | public void RemoveVehiclePrim(BSPrim vehicle) | ||
908 | { | ||
909 | lock (m_vehicles) | ||
910 | { | ||
911 | if (m_vehicles.Contains(vehicle)) | ||
912 | { | ||
913 | m_vehicles.Remove(vehicle); | ||
914 | } | ||
915 | } | ||
916 | } | ||
917 | |||
918 | // Some prims have extra vehicle actions | ||
919 | // Called at taint time! | ||
920 | private void ProcessVehicles(float timeStep) | ||
921 | { | ||
922 | foreach (BSPhysObject pobj in m_vehicles) | ||
923 | { | ||
924 | pobj.StepVehicle(timeStep); | ||
925 | } | ||
926 | } | ||
927 | #endregion Vehicles | ||
928 | |||
929 | #region INI and command line parameter processing | 835 | #region INI and command line parameter processing |
930 | 836 | ||
931 | delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); | ||
932 | delegate float ParamGet(BSScene scene); | ||
933 | delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); | ||
934 | delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val); | ||
935 | |||
936 | private struct ParameterDefn | ||
937 | { | ||
938 | public string name; // string name of the parameter | ||
939 | public string desc; // a short description of what the parameter means | ||
940 | public float defaultValue; // default value if not specified anywhere else | ||
941 | public ParamUser userParam; // get the value from the configuration file | ||
942 | public ParamGet getter; // return the current value stored for this parameter | ||
943 | public ParamSet setter; // set the current value for this parameter | ||
944 | public SetOnObject onObject; // set the value on an object in the physical domain | ||
945 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) | ||
946 | { | ||
947 | name = n; | ||
948 | desc = d; | ||
949 | defaultValue = v; | ||
950 | userParam = u; | ||
951 | getter = g; | ||
952 | setter = s; | ||
953 | onObject = null; | ||
954 | } | ||
955 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o) | ||
956 | { | ||
957 | name = n; | ||
958 | desc = d; | ||
959 | defaultValue = v; | ||
960 | userParam = u; | ||
961 | getter = g; | ||
962 | setter = s; | ||
963 | onObject = o; | ||
964 | } | ||
965 | } | ||
966 | |||
967 | // List of all of the externally visible parameters. | ||
968 | // For each parameter, this table maps a text name to getter and setters. | ||
969 | // To add a new externally referencable/settable parameter, add the paramter storage | ||
970 | // location somewhere in the program and make an entry in this table with the | ||
971 | // getters and setters. | ||
972 | // It is easiest to find an existing definition and copy it. | ||
973 | // Parameter values are floats. Booleans are converted to a floating value. | ||
974 | // | ||
975 | // A ParameterDefn() takes the following parameters: | ||
976 | // -- the text name of the parameter. This is used for console input and ini file. | ||
977 | // -- a short text description of the parameter. This shows up in the console listing. | ||
978 | // -- a delegate for fetching the parameter from the ini file. | ||
979 | // Should handle fetching the right type from the ini file and converting it. | ||
980 | // -- a delegate for getting the value as a float | ||
981 | // -- a delegate for setting the value from a float | ||
982 | // | ||
983 | // The single letter parameters for the delegates are: | ||
984 | // s = BSScene | ||
985 | // o = BSPhysObject | ||
986 | // p = string parameter name | ||
987 | // l = localID of referenced object | ||
988 | // v = float value | ||
989 | // cf = parameter configuration class (for fetching values from ini file) | ||
990 | private ParameterDefn[] ParameterDefinitions = | ||
991 | { | ||
992 | new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", | ||
993 | ConfigurationParameters.numericTrue, | ||
994 | (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, | ||
995 | (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); }, | ||
996 | (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ), | ||
997 | new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", | ||
998 | ConfigurationParameters.numericFalse, | ||
999 | (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, | ||
1000 | (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); }, | ||
1001 | (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ), | ||
1002 | new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", | ||
1003 | ConfigurationParameters.numericTrue, | ||
1004 | (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); }, | ||
1005 | (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); }, | ||
1006 | (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ), | ||
1007 | |||
1008 | new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | ||
1009 | 8f, | ||
1010 | (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); }, | ||
1011 | (s) => { return s.MeshLOD; }, | ||
1012 | (s,p,l,v) => { s.MeshLOD = v; } ), | ||
1013 | new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", | ||
1014 | 16f, | ||
1015 | (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); }, | ||
1016 | (s) => { return s.MeshMegaPrimLOD; }, | ||
1017 | (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ), | ||
1018 | new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", | ||
1019 | 10f, | ||
1020 | (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); }, | ||
1021 | (s) => { return s.MeshMegaPrimThreshold; }, | ||
1022 | (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ), | ||
1023 | new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", | ||
1024 | 32f, | ||
1025 | (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); }, | ||
1026 | (s) => { return s.SculptLOD; }, | ||
1027 | (s,p,l,v) => { s.SculptLOD = v; } ), | ||
1028 | |||
1029 | new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", | ||
1030 | 10f, | ||
1031 | (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); }, | ||
1032 | (s) => { return (float)s.m_maxSubSteps; }, | ||
1033 | (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ), | ||
1034 | new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", | ||
1035 | 1f / 60f, | ||
1036 | (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); }, | ||
1037 | (s) => { return (float)s.m_fixedTimeStep; }, | ||
1038 | (s,p,l,v) => { s.m_fixedTimeStep = v; } ), | ||
1039 | new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", | ||
1040 | 2048f, | ||
1041 | (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); }, | ||
1042 | (s) => { return (float)s.m_maxCollisionsPerFrame; }, | ||
1043 | (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), | ||
1044 | new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame", | ||
1045 | 8000f, | ||
1046 | (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, | ||
1047 | (s) => { return (float)s.m_maxUpdatesPerFrame; }, | ||
1048 | (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), | ||
1049 | new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", | ||
1050 | 500f, | ||
1051 | (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, | ||
1052 | (s) => { return (float)s.m_taintsToProcessPerStep; }, | ||
1053 | (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), | ||
1054 | new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", | ||
1055 | 10000.01f, | ||
1056 | (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); }, | ||
1057 | (s) => { return (float)s.MaximumObjectMass; }, | ||
1058 | (s,p,l,v) => { s.MaximumObjectMass = v; } ), | ||
1059 | |||
1060 | new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", | ||
1061 | 2200f, | ||
1062 | (s,cf,p,v) => { s.PID_D = cf.GetFloat(p, v); }, | ||
1063 | (s) => { return (float)s.PID_D; }, | ||
1064 | (s,p,l,v) => { s.PID_D = v; } ), | ||
1065 | new ParameterDefn("PID_P", "Parameteric factor for motion smoothing", | ||
1066 | 900f, | ||
1067 | (s,cf,p,v) => { s.PID_P = cf.GetFloat(p, v); }, | ||
1068 | (s) => { return (float)s.PID_P; }, | ||
1069 | (s,p,l,v) => { s.PID_P = v; } ), | ||
1070 | |||
1071 | new ParameterDefn("DefaultFriction", "Friction factor used on new objects", | ||
1072 | 0.5f, | ||
1073 | (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, | ||
1074 | (s) => { return s.m_params[0].defaultFriction; }, | ||
1075 | (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), | ||
1076 | new ParameterDefn("DefaultDensity", "Density for new objects" , | ||
1077 | 10.000006836f, // Aluminum g/cm3 | ||
1078 | (s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); }, | ||
1079 | (s) => { return s.m_params[0].defaultDensity; }, | ||
1080 | (s,p,l,v) => { s.m_params[0].defaultDensity = v; } ), | ||
1081 | new ParameterDefn("DefaultRestitution", "Bouncyness of an object" , | ||
1082 | 0f, | ||
1083 | (s,cf,p,v) => { s.m_params[0].defaultRestitution = cf.GetFloat(p, v); }, | ||
1084 | (s) => { return s.m_params[0].defaultRestitution; }, | ||
1085 | (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), | ||
1086 | new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", | ||
1087 | 0f, | ||
1088 | (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, | ||
1089 | (s) => { return s.m_params[0].collisionMargin; }, | ||
1090 | (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), | ||
1091 | new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)", | ||
1092 | -9.80665f, | ||
1093 | (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, | ||
1094 | (s) => { return s.m_params[0].gravity; }, | ||
1095 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); }, | ||
1096 | (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ), | ||
1097 | |||
1098 | |||
1099 | new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", | ||
1100 | 0f, | ||
1101 | (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, | ||
1102 | (s) => { return s.m_params[0].linearDamping; }, | ||
1103 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); }, | ||
1104 | (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, s.m_params[0].angularDamping); } ), | ||
1105 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", | ||
1106 | 0f, | ||
1107 | (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, | ||
1108 | (s) => { return s.m_params[0].angularDamping; }, | ||
1109 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); }, | ||
1110 | (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, s.m_params[0].linearDamping, v); } ), | ||
1111 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", | ||
1112 | 0.2f, | ||
1113 | (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, | ||
1114 | (s) => { return s.m_params[0].deactivationTime; }, | ||
1115 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); }, | ||
1116 | (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ), | ||
1117 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", | ||
1118 | 0.8f, | ||
1119 | (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, | ||
1120 | (s) => { return s.m_params[0].linearSleepingThreshold; }, | ||
1121 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); }, | ||
1122 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), | ||
1123 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", | ||
1124 | 1.0f, | ||
1125 | (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, | ||
1126 | (s) => { return s.m_params[0].angularSleepingThreshold; }, | ||
1127 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); }, | ||
1128 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), | ||
1129 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , | ||
1130 | 0f, // set to zero to disable | ||
1131 | (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, | ||
1132 | (s) => { return s.m_params[0].ccdMotionThreshold; }, | ||
1133 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); }, | ||
1134 | (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ), | ||
1135 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , | ||
1136 | 0f, | ||
1137 | (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, | ||
1138 | (s) => { return s.m_params[0].ccdSweptSphereRadius; }, | ||
1139 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); }, | ||
1140 | (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ), | ||
1141 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , | ||
1142 | 0.1f, | ||
1143 | (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, | ||
1144 | (s) => { return s.m_params[0].contactProcessingThreshold; }, | ||
1145 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); }, | ||
1146 | (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ), | ||
1147 | |||
1148 | new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", | ||
1149 | (float)BSTerrainPhys.TerrainImplementation.Mesh, | ||
1150 | (s,cf,p,v) => { s.m_params[0].terrainImplementation = cf.GetFloat(p,v); }, | ||
1151 | (s) => { return s.m_params[0].terrainImplementation; }, | ||
1152 | (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), | ||
1153 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | ||
1154 | 0.5f, | ||
1155 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, | ||
1156 | (s) => { return s.m_params[0].terrainFriction; }, | ||
1157 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), | ||
1158 | new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , | ||
1159 | 0.8f, | ||
1160 | (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, | ||
1161 | (s) => { return s.m_params[0].terrainHitFraction; }, | ||
1162 | (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ), | ||
1163 | new ParameterDefn("TerrainRestitution", "Bouncyness" , | ||
1164 | 0f, | ||
1165 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, | ||
1166 | (s) => { return s.m_params[0].terrainRestitution; }, | ||
1167 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), | ||
1168 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | ||
1169 | 0.2f, | ||
1170 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, | ||
1171 | (s) => { return s.m_params[0].avatarFriction; }, | ||
1172 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), | ||
1173 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | ||
1174 | 10f, | ||
1175 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, | ||
1176 | (s) => { return s.m_params[0].avatarStandingFriction; }, | ||
1177 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), | ||
1178 | new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | ||
1179 | 60f, | ||
1180 | (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, | ||
1181 | (s) => { return s.m_params[0].avatarDensity; }, | ||
1182 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ), | ||
1183 | new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", | ||
1184 | 0f, | ||
1185 | (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, | ||
1186 | (s) => { return s.m_params[0].avatarRestitution; }, | ||
1187 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ), | ||
1188 | new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", | ||
1189 | 0.6f, | ||
1190 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleWidth = cf.GetFloat(p, v); }, | ||
1191 | (s) => { return s.m_params[0].avatarCapsuleWidth; }, | ||
1192 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleWidth, p, l, v); } ), | ||
1193 | new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", | ||
1194 | 0.45f, | ||
1195 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleDepth = cf.GetFloat(p, v); }, | ||
1196 | (s) => { return s.m_params[0].avatarCapsuleDepth; }, | ||
1197 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleDepth, p, l, v); } ), | ||
1198 | new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", | ||
1199 | 1.5f, | ||
1200 | (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, | ||
1201 | (s) => { return s.m_params[0].avatarCapsuleHeight; }, | ||
1202 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), | ||
1203 | new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | ||
1204 | 0.1f, | ||
1205 | (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, | ||
1206 | (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, | ||
1207 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), | ||
1208 | |||
1209 | |||
1210 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | ||
1211 | 0f, | ||
1212 | (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, | ||
1213 | (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, | ||
1214 | (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), | ||
1215 | new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", | ||
1216 | 0f, | ||
1217 | (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, | ||
1218 | (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; }, | ||
1219 | (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ), | ||
1220 | new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", | ||
1221 | ConfigurationParameters.numericFalse, | ||
1222 | (s,cf,p,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1223 | (s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; }, | ||
1224 | (s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ), | ||
1225 | new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", | ||
1226 | ConfigurationParameters.numericFalse, | ||
1227 | (s,cf,p,v) => { s.m_params[0].shouldForceUpdateAllAabbs = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1228 | (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; }, | ||
1229 | (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ), | ||
1230 | new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", | ||
1231 | ConfigurationParameters.numericTrue, | ||
1232 | (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1233 | (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, | ||
1234 | (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), | ||
1235 | new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", | ||
1236 | ConfigurationParameters.numericTrue, | ||
1237 | (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1238 | (s) => { return s.m_params[0].shouldSplitSimulationIslands; }, | ||
1239 | (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), | ||
1240 | new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching", | ||
1241 | ConfigurationParameters.numericFalse, | ||
1242 | (s,cf,p,v) => { s.m_params[0].shouldEnableFrictionCaching = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1243 | (s) => { return s.m_params[0].shouldEnableFrictionCaching; }, | ||
1244 | (s,p,l,v) => { s.m_params[0].shouldEnableFrictionCaching = v; } ), | ||
1245 | new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)", | ||
1246 | 0f, // zero says use Bullet default | ||
1247 | (s,cf,p,v) => { s.m_params[0].numberOfSolverIterations = cf.GetFloat(p, v); }, | ||
1248 | (s) => { return s.m_params[0].numberOfSolverIterations; }, | ||
1249 | (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), | ||
1250 | |||
1251 | new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | ||
1252 | (float)BSLinkset.LinksetImplementation.Compound, | ||
1253 | (s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); }, | ||
1254 | (s) => { return s.m_params[0].linksetImplementation; }, | ||
1255 | (s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ), | ||
1256 | new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | ||
1257 | ConfigurationParameters.numericFalse, | ||
1258 | (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1259 | (s) => { return s.m_params[0].linkConstraintUseFrameOffset; }, | ||
1260 | (s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ), | ||
1261 | new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", | ||
1262 | ConfigurationParameters.numericTrue, | ||
1263 | (s,cf,p,v) => { s.m_params[0].linkConstraintEnableTransMotor = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | ||
1264 | (s) => { return s.m_params[0].linkConstraintEnableTransMotor; }, | ||
1265 | (s,p,l,v) => { s.m_params[0].linkConstraintEnableTransMotor = v; } ), | ||
1266 | new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", | ||
1267 | 5.0f, | ||
1268 | (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = cf.GetFloat(p, v); }, | ||
1269 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxVel; }, | ||
1270 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = v; } ), | ||
1271 | new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", | ||
1272 | 0.1f, | ||
1273 | (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, | ||
1274 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, | ||
1275 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), | ||
1276 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | ||
1277 | 0.1f, | ||
1278 | (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, | ||
1279 | (s) => { return s.m_params[0].linkConstraintCFM; }, | ||
1280 | (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), | ||
1281 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | ||
1282 | 0.1f, | ||
1283 | (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, | ||
1284 | (s) => { return s.m_params[0].linkConstraintERP; }, | ||
1285 | (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), | ||
1286 | new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", | ||
1287 | 40, | ||
1288 | (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); }, | ||
1289 | (s) => { return s.m_params[0].linkConstraintSolverIterations; }, | ||
1290 | (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ), | ||
1291 | |||
1292 | new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)", | ||
1293 | 0f, | ||
1294 | (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); }, | ||
1295 | (s) => { return (float)s.m_params[0].physicsLoggingFrames; }, | ||
1296 | (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ), | ||
1297 | }; | ||
1298 | |||
1299 | // Convert a boolean to our numeric true and false values | ||
1300 | public float NumericBool(bool b) | ||
1301 | { | ||
1302 | return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse); | ||
1303 | } | ||
1304 | |||
1305 | // Convert numeric true and false values to a boolean | ||
1306 | public bool BoolNumeric(float b) | ||
1307 | { | ||
1308 | return (b == ConfigurationParameters.numericTrue ? true : false); | ||
1309 | } | ||
1310 | |||
1311 | // Search through the parameter definitions and return the matching | ||
1312 | // ParameterDefn structure. | ||
1313 | // Case does not matter as names are compared after converting to lower case. | ||
1314 | // Returns 'false' if the parameter is not found. | ||
1315 | private bool TryGetParameter(string paramName, out ParameterDefn defn) | ||
1316 | { | ||
1317 | bool ret = false; | ||
1318 | ParameterDefn foundDefn = new ParameterDefn(); | ||
1319 | string pName = paramName.ToLower(); | ||
1320 | |||
1321 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
1322 | { | ||
1323 | if (pName == parm.name.ToLower()) | ||
1324 | { | ||
1325 | foundDefn = parm; | ||
1326 | ret = true; | ||
1327 | break; | ||
1328 | } | ||
1329 | } | ||
1330 | defn = foundDefn; | ||
1331 | return ret; | ||
1332 | } | ||
1333 | |||
1334 | // Pass through the settable parameters and set the default values | ||
1335 | private void SetParameterDefaultValues() | ||
1336 | { | ||
1337 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
1338 | { | ||
1339 | parm.setter(this, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue); | ||
1340 | } | ||
1341 | } | ||
1342 | |||
1343 | // Get user set values out of the ini file. | ||
1344 | private void SetParameterConfigurationValues(IConfig cfg) | ||
1345 | { | ||
1346 | foreach (ParameterDefn parm in ParameterDefinitions) | ||
1347 | { | ||
1348 | parm.userParam(this, cfg, parm.name, parm.defaultValue); | ||
1349 | } | ||
1350 | } | ||
1351 | |||
1352 | private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; | ||
1353 | |||
1354 | // This creates an array in the correct format for returning the list of | ||
1355 | // parameters. This is used by the 'list' option of the 'physics' command. | ||
1356 | private void BuildParameterTable() | ||
1357 | { | ||
1358 | if (SettableParameters.Length < ParameterDefinitions.Length) | ||
1359 | { | ||
1360 | List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); | ||
1361 | for (int ii = 0; ii < ParameterDefinitions.Length; ii++) | ||
1362 | { | ||
1363 | ParameterDefn pd = ParameterDefinitions[ii]; | ||
1364 | entries.Add(new PhysParameterEntry(pd.name, pd.desc)); | ||
1365 | } | ||
1366 | |||
1367 | // make the list in alphabetical order for estetic reasons | ||
1368 | entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2) | ||
1369 | { | ||
1370 | return ppe1.name.CompareTo(ppe2.name); | ||
1371 | }); | ||
1372 | |||
1373 | SettableParameters = entries.ToArray(); | ||
1374 | } | ||
1375 | } | ||
1376 | |||
1377 | |||
1378 | #region IPhysicsParameters | 837 | #region IPhysicsParameters |
1379 | // Get the list of parameters this physics engine supports | 838 | // Get the list of parameters this physics engine supports |
1380 | public PhysParameterEntry[] GetParameterList() | 839 | public PhysParameterEntry[] GetParameterList() |
1381 | { | 840 | { |
1382 | BuildParameterTable(); | 841 | BSParam.BuildParameterTable(); |
1383 | return SettableParameters; | 842 | return BSParam.SettableParameters; |
1384 | } | 843 | } |
1385 | 844 | ||
1386 | // Set parameter on a specific or all instances. | 845 | // Set parameter on a specific or all instances. |
@@ -1392,8 +851,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1392 | public bool SetPhysicsParameter(string parm, float val, uint localID) | 851 | public bool SetPhysicsParameter(string parm, float val, uint localID) |
1393 | { | 852 | { |
1394 | bool ret = false; | 853 | bool ret = false; |
1395 | ParameterDefn theParam; | 854 | BSParam.ParameterDefn theParam; |
1396 | if (TryGetParameter(parm, out theParam)) | 855 | if (BSParam.TryGetParameter(parm, out theParam)) |
1397 | { | 856 | { |
1398 | theParam.setter(this, parm, localID, val); | 857 | theParam.setter(this, parm, localID, val); |
1399 | ret = true; | 858 | ret = true; |
@@ -1405,19 +864,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1405 | // If the local ID is APPLY_TO_NONE, just change the default value | 864 | // If the local ID is APPLY_TO_NONE, just change the default value |
1406 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs | 865 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs |
1407 | // If the localID is a specific object, apply the parameter change to only that object | 866 | // If the localID is a specific object, apply the parameter change to only that object |
1408 | private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val) | 867 | internal delegate void AssignVal(float x); |
868 | internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val) | ||
1409 | { | 869 | { |
1410 | List<uint> objectIDs = new List<uint>(); | 870 | List<uint> objectIDs = new List<uint>(); |
1411 | switch (localID) | 871 | switch (localID) |
1412 | { | 872 | { |
1413 | case PhysParameterEntry.APPLY_TO_NONE: | 873 | case PhysParameterEntry.APPLY_TO_NONE: |
1414 | defaultLoc = val; // setting only the default value | 874 | setDefault(val); // setting only the default value |
1415 | // This will cause a call into the physical world if some operation is specified (SetOnObject). | 875 | // This will cause a call into the physical world if some operation is specified (SetOnObject). |
1416 | objectIDs.Add(TERRAIN_ID); | 876 | objectIDs.Add(TERRAIN_ID); |
1417 | TaintedUpdateParameter(parm, objectIDs, val); | 877 | TaintedUpdateParameter(parm, objectIDs, val); |
1418 | break; | 878 | break; |
1419 | case PhysParameterEntry.APPLY_TO_ALL: | 879 | case PhysParameterEntry.APPLY_TO_ALL: |
1420 | defaultLoc = val; // setting ALL also sets the default value | 880 | setDefault(val); // setting ALL also sets the default value |
1421 | lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); | 881 | lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); |
1422 | TaintedUpdateParameter(parm, objectIDs, val); | 882 | TaintedUpdateParameter(parm, objectIDs, val); |
1423 | break; | 883 | break; |
@@ -1436,8 +896,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1436 | List<uint> xlIDs = lIDs; | 896 | List<uint> xlIDs = lIDs; |
1437 | string xparm = parm; | 897 | string xparm = parm; |
1438 | TaintedObject("BSScene.UpdateParameterSet", delegate() { | 898 | TaintedObject("BSScene.UpdateParameterSet", delegate() { |
1439 | ParameterDefn thisParam; | 899 | BSParam.ParameterDefn thisParam; |
1440 | if (TryGetParameter(xparm, out thisParam)) | 900 | if (BSParam.TryGetParameter(xparm, out thisParam)) |
1441 | { | 901 | { |
1442 | if (thisParam.onObject != null) | 902 | if (thisParam.onObject != null) |
1443 | { | 903 | { |
@@ -1458,8 +918,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1458 | { | 918 | { |
1459 | float val = 0f; | 919 | float val = 0f; |
1460 | bool ret = false; | 920 | bool ret = false; |
1461 | ParameterDefn theParam; | 921 | BSParam.ParameterDefn theParam; |
1462 | if (TryGetParameter(parm, out theParam)) | 922 | if (BSParam.TryGetParameter(parm, out theParam)) |
1463 | { | 923 | { |
1464 | val = theParam.getter(this); | 924 | val = theParam.getter(this); |
1465 | ret = true; | 925 | ret = true; |
@@ -1472,22 +932,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1472 | 932 | ||
1473 | #endregion Runtime settable parameters | 933 | #endregion Runtime settable parameters |
1474 | 934 | ||
1475 | // Debugging routine for dumping detailed physical information for vehicle prims | ||
1476 | private void DumpVehicles() | ||
1477 | { | ||
1478 | foreach (BSPrim prim in m_vehicles) | ||
1479 | { | ||
1480 | BulletSimAPI.DumpRigidBody2(World.ptr, prim.PhysBody.ptr); | ||
1481 | BulletSimAPI.DumpCollisionShape2(World.ptr, prim.PhysShape.ptr); | ||
1482 | } | ||
1483 | } | ||
1484 | |||
1485 | // Invoke the detailed logger and output something if it's enabled. | 935 | // Invoke the detailed logger and output something if it's enabled. |
1486 | public void DetailLog(string msg, params Object[] args) | 936 | public void DetailLog(string msg, params Object[] args) |
1487 | { | 937 | { |
1488 | PhysicsLogging.Write(msg, args); | 938 | PhysicsLogging.Write(msg, args); |
1489 | // Add the Flush() if debugging crashes. Gets all the messages written out. | 939 | // Add the Flush() if debugging crashes. Gets all the messages written out. |
1490 | // PhysicsLogging.Flush(); | 940 | if (m_physicsLoggingDoFlush) PhysicsLogging.Flush(); |
1491 | } | 941 | } |
1492 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. | 942 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. |
1493 | public const string DetailLogZero = "0000000000"; | 943 | public const string DetailLogZero = "0000000000"; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 892c34b..b4f764b 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -45,7 +45,7 @@ public sealed class BSShapeCollection : IDisposable | |||
45 | // Description of a Mesh | 45 | // Description of a Mesh |
46 | private struct MeshDesc | 46 | private struct MeshDesc |
47 | { | 47 | { |
48 | public IntPtr ptr; | 48 | public BulletShape shape; |
49 | public int referenceCount; | 49 | public int referenceCount; |
50 | public DateTime lastReferenced; | 50 | public DateTime lastReferenced; |
51 | public UInt64 shapeKey; | 51 | public UInt64 shapeKey; |
@@ -55,7 +55,7 @@ public sealed class BSShapeCollection : IDisposable | |||
55 | // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. | 55 | // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. |
56 | private struct HullDesc | 56 | private struct HullDesc |
57 | { | 57 | { |
58 | public IntPtr ptr; | 58 | public BulletShape shape; |
59 | public int referenceCount; | 59 | public int referenceCount; |
60 | public DateTime lastReferenced; | 60 | public DateTime lastReferenced; |
61 | public UInt64 shapeKey; | 61 | public UInt64 shapeKey; |
@@ -65,9 +65,16 @@ public sealed class BSShapeCollection : IDisposable | |||
65 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); | 65 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); |
66 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); | 66 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); |
67 | 67 | ||
68 | private bool DDetail = false; | ||
69 | |||
68 | public BSShapeCollection(BSScene physScene) | 70 | public BSShapeCollection(BSScene physScene) |
69 | { | 71 | { |
70 | PhysicsScene = physScene; | 72 | PhysicsScene = physScene; |
73 | // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) | ||
74 | // While detailed debugging is still active, this is better than commenting out all the | ||
75 | // DetailLog statements. When debugging slows down, this and the protected logging | ||
76 | // statements can be commented/removed. | ||
77 | DDetail = true; | ||
71 | } | 78 | } |
72 | 79 | ||
73 | public void Dispose() | 80 | public void Dispose() |
@@ -91,7 +98,7 @@ public sealed class BSShapeCollection : IDisposable | |||
91 | // higher level dependencies on the shape or body. Mostly used for LinkSets to | 98 | // higher level dependencies on the shape or body. Mostly used for LinkSets to |
92 | // remove the physical constraints before the body is destroyed. | 99 | // remove the physical constraints before the body is destroyed. |
93 | // Called at taint-time!! | 100 | // Called at taint-time!! |
94 | public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, | 101 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, |
95 | ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) | 102 | ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) |
96 | { | 103 | { |
97 | PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); | 104 | PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); |
@@ -119,6 +126,11 @@ public sealed class BSShapeCollection : IDisposable | |||
119 | return ret; | 126 | return ret; |
120 | } | 127 | } |
121 | 128 | ||
129 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) | ||
130 | { | ||
131 | return GetBodyAndShape(forceRebuild, sim, prim, null, null); | ||
132 | } | ||
133 | |||
122 | // Track another user of a body. | 134 | // Track another user of a body. |
123 | // We presume the caller has allocated the body. | 135 | // We presume the caller has allocated the body. |
124 | // Bodies only have one user so the body is just put into the world if not already there. | 136 | // Bodies only have one user so the body is just put into the world if not already there. |
@@ -126,13 +138,13 @@ public sealed class BSShapeCollection : IDisposable | |||
126 | { | 138 | { |
127 | lock (m_collectionActivityLock) | 139 | lock (m_collectionActivityLock) |
128 | { | 140 | { |
129 | DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); | 141 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); |
130 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() | 142 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() |
131 | { | 143 | { |
132 | if (!BulletSimAPI.IsInWorld2(body.ptr)) | 144 | if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) |
133 | { | 145 | { |
134 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); | 146 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body); |
135 | DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); | 147 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); |
136 | } | 148 | } |
137 | }); | 149 | }); |
138 | } | 150 | } |
@@ -142,27 +154,27 @@ public sealed class BSShapeCollection : IDisposable | |||
142 | // Called when releasing use of a BSBody. BSShape is handled separately. | 154 | // Called when releasing use of a BSBody. BSShape is handled separately. |
143 | public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) | 155 | public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) |
144 | { | 156 | { |
145 | if (body.ptr == IntPtr.Zero) | 157 | if (!body.HasPhysicalBody) |
146 | return; | 158 | return; |
147 | 159 | ||
148 | lock (m_collectionActivityLock) | 160 | lock (m_collectionActivityLock) |
149 | { | 161 | { |
150 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() | 162 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() |
151 | { | 163 | { |
152 | DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", | 164 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", |
153 | body.ID, body, inTaintTime); | 165 | body.ID, body, inTaintTime); |
154 | // If the caller needs to know the old body is going away, pass the event up. | 166 | // If the caller needs to know the old body is going away, pass the event up. |
155 | if (bodyCallback != null) bodyCallback(body); | 167 | if (bodyCallback != null) bodyCallback(body); |
156 | 168 | ||
157 | if (BulletSimAPI.IsInWorld2(body.ptr)) | 169 | if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) |
158 | { | 170 | { |
159 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); | 171 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body); |
160 | DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); | 172 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); |
161 | } | 173 | } |
162 | 174 | ||
163 | // Zero any reference to the shape so it is not freed when the body is deleted. | 175 | // Zero any reference to the shape so it is not freed when the body is deleted. |
164 | BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); | 176 | PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null); |
165 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); | 177 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, body); |
166 | }); | 178 | }); |
167 | } | 179 | } |
168 | } | 180 | } |
@@ -184,17 +196,17 @@ public sealed class BSShapeCollection : IDisposable | |||
184 | { | 196 | { |
185 | // There is an existing instance of this mesh. | 197 | // There is an existing instance of this mesh. |
186 | meshDesc.referenceCount++; | 198 | meshDesc.referenceCount++; |
187 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", | 199 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", |
188 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 200 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
189 | } | 201 | } |
190 | else | 202 | else |
191 | { | 203 | { |
192 | // This is a new reference to a mesh | 204 | // This is a new reference to a mesh |
193 | meshDesc.ptr = shape.ptr; | 205 | meshDesc.shape = shape.Clone(); |
194 | meshDesc.shapeKey = shape.shapeKey; | 206 | meshDesc.shapeKey = shape.shapeKey; |
195 | // We keep a reference to the underlying IMesh data so a hull can be built | 207 | // We keep a reference to the underlying IMesh data so a hull can be built |
196 | meshDesc.referenceCount = 1; | 208 | meshDesc.referenceCount = 1; |
197 | DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", | 209 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", |
198 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 210 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
199 | ret = true; | 211 | ret = true; |
200 | } | 212 | } |
@@ -207,16 +219,16 @@ public sealed class BSShapeCollection : IDisposable | |||
207 | { | 219 | { |
208 | // There is an existing instance of this hull. | 220 | // There is an existing instance of this hull. |
209 | hullDesc.referenceCount++; | 221 | hullDesc.referenceCount++; |
210 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", | 222 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", |
211 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 223 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
212 | } | 224 | } |
213 | else | 225 | else |
214 | { | 226 | { |
215 | // This is a new reference to a hull | 227 | // This is a new reference to a hull |
216 | hullDesc.ptr = shape.ptr; | 228 | hullDesc.shape = shape.Clone(); |
217 | hullDesc.shapeKey = shape.shapeKey; | 229 | hullDesc.shapeKey = shape.shapeKey; |
218 | hullDesc.referenceCount = 1; | 230 | hullDesc.referenceCount = 1; |
219 | DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", | 231 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", |
220 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 232 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
221 | ret = true; | 233 | ret = true; |
222 | 234 | ||
@@ -236,20 +248,20 @@ public sealed class BSShapeCollection : IDisposable | |||
236 | // Release the usage of a shape. | 248 | // Release the usage of a shape. |
237 | public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) | 249 | public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) |
238 | { | 250 | { |
239 | if (shape.ptr == IntPtr.Zero) | 251 | if (!shape.HasPhysicalShape) |
240 | return; | 252 | return; |
241 | 253 | ||
242 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() | 254 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() |
243 | { | 255 | { |
244 | if (shape.ptr != IntPtr.Zero) | 256 | if (shape.HasPhysicalShape) |
245 | { | 257 | { |
246 | if (shape.isNativeShape) | 258 | if (shape.isNativeShape) |
247 | { | 259 | { |
248 | // Native shapes are not tracked and are released immediately | 260 | // Native shapes are not tracked and are released immediately |
249 | DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", | 261 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", |
250 | BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); | 262 | BSScene.DetailLogZero, shape.AddrString, inTaintTime); |
251 | if (shapeCallback != null) shapeCallback(shape); | 263 | if (shapeCallback != null) shapeCallback(shape); |
252 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | 264 | PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); |
253 | } | 265 | } |
254 | else | 266 | else |
255 | { | 267 | { |
@@ -286,7 +298,7 @@ public sealed class BSShapeCollection : IDisposable | |||
286 | if (shapeCallback != null) shapeCallback(shape); | 298 | if (shapeCallback != null) shapeCallback(shape); |
287 | meshDesc.lastReferenced = System.DateTime.Now; | 299 | meshDesc.lastReferenced = System.DateTime.Now; |
288 | Meshes[shape.shapeKey] = meshDesc; | 300 | Meshes[shape.shapeKey] = meshDesc; |
289 | DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", | 301 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", |
290 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); | 302 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); |
291 | 303 | ||
292 | } | 304 | } |
@@ -307,7 +319,7 @@ public sealed class BSShapeCollection : IDisposable | |||
307 | 319 | ||
308 | hullDesc.lastReferenced = System.DateTime.Now; | 320 | hullDesc.lastReferenced = System.DateTime.Now; |
309 | Hulls[shape.shapeKey] = hullDesc; | 321 | Hulls[shape.shapeKey] = hullDesc; |
310 | DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", | 322 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", |
311 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); | 323 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); |
312 | } | 324 | } |
313 | } | 325 | } |
@@ -320,57 +332,56 @@ public sealed class BSShapeCollection : IDisposable | |||
320 | // Called at taint-time. | 332 | // Called at taint-time. |
321 | private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) | 333 | private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) |
322 | { | 334 | { |
323 | if (!BulletSimAPI.IsCompound2(shape.ptr)) | 335 | if (!PhysicsScene.PE.IsCompound(shape)) |
324 | { | 336 | { |
325 | // Failed the sanity check!! | 337 | // Failed the sanity check!! |
326 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | 338 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", |
327 | LogHeader, shape.type, shape.ptr.ToString("X")); | 339 | LogHeader, shape.type, shape.AddrString); |
328 | DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | 340 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", |
329 | BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); | 341 | BSScene.DetailLogZero, shape.type, shape.AddrString); |
330 | return; | 342 | return; |
331 | } | 343 | } |
332 | 344 | ||
333 | int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); | 345 | int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape); |
334 | DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); | 346 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); |
335 | 347 | ||
336 | for (int ii = numChildren - 1; ii >= 0; ii--) | 348 | for (int ii = numChildren - 1; ii >= 0; ii--) |
337 | { | 349 | { |
338 | IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii); | 350 | BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii); |
339 | DereferenceAnonCollisionShape(childShape); | 351 | DereferenceAnonCollisionShape(childShape); |
340 | } | 352 | } |
341 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | 353 | PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); |
342 | } | 354 | } |
343 | 355 | ||
344 | // Sometimes we have a pointer to a collision shape but don't know what type it is. | 356 | // Sometimes we have a pointer to a collision shape but don't know what type it is. |
345 | // Figure out type and call the correct dereference routine. | 357 | // Figure out type and call the correct dereference routine. |
346 | // Called at taint-time. | 358 | // Called at taint-time. |
347 | private void DereferenceAnonCollisionShape(IntPtr cShape) | 359 | private void DereferenceAnonCollisionShape(BulletShape shapeInfo) |
348 | { | 360 | { |
349 | MeshDesc meshDesc; | 361 | MeshDesc meshDesc; |
350 | HullDesc hullDesc; | 362 | HullDesc hullDesc; |
351 | 363 | ||
352 | BulletShape shapeInfo = new BulletShape(cShape); | 364 | if (TryGetMeshByPtr(shapeInfo, out meshDesc)) |
353 | if (TryGetMeshByPtr(cShape, out meshDesc)) | ||
354 | { | 365 | { |
355 | shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; | 366 | shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; |
356 | shapeInfo.shapeKey = meshDesc.shapeKey; | 367 | shapeInfo.shapeKey = meshDesc.shapeKey; |
357 | } | 368 | } |
358 | else | 369 | else |
359 | { | 370 | { |
360 | if (TryGetHullByPtr(cShape, out hullDesc)) | 371 | if (TryGetHullByPtr(shapeInfo, out hullDesc)) |
361 | { | 372 | { |
362 | shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; | 373 | shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; |
363 | shapeInfo.shapeKey = hullDesc.shapeKey; | 374 | shapeInfo.shapeKey = hullDesc.shapeKey; |
364 | } | 375 | } |
365 | else | 376 | else |
366 | { | 377 | { |
367 | if (BulletSimAPI.IsCompound2(cShape)) | 378 | if (PhysicsScene.PE.IsCompound(shapeInfo)) |
368 | { | 379 | { |
369 | shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; | 380 | shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; |
370 | } | 381 | } |
371 | else | 382 | else |
372 | { | 383 | { |
373 | if (BulletSimAPI.IsNativeShape2(cShape)) | 384 | if (PhysicsScene.PE.IsNativeShape(shapeInfo)) |
374 | { | 385 | { |
375 | shapeInfo.isNativeShape = true; | 386 | shapeInfo.isNativeShape = true; |
376 | shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) | 387 | shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) |
@@ -379,7 +390,7 @@ public sealed class BSShapeCollection : IDisposable | |||
379 | } | 390 | } |
380 | } | 391 | } |
381 | 392 | ||
382 | DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); | 393 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); |
383 | 394 | ||
384 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) | 395 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) |
385 | { | 396 | { |
@@ -388,7 +399,7 @@ public sealed class BSShapeCollection : IDisposable | |||
388 | else | 399 | else |
389 | { | 400 | { |
390 | PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", | 401 | PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", |
391 | LogHeader, PhysicsScene.RegionName, cShape.ToString("X")); | 402 | LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString); |
392 | } | 403 | } |
393 | } | 404 | } |
394 | 405 | ||
@@ -408,19 +419,18 @@ public sealed class BSShapeCollection : IDisposable | |||
408 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) | 419 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) |
409 | { | 420 | { |
410 | // an avatar capsule is close to a native shape (it is not shared) | 421 | // an avatar capsule is close to a native shape (it is not shared) |
411 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, | 422 | GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback); |
412 | FixedShapeKey.KEY_CAPSULE, shapeCallback); | 423 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); |
413 | DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); | ||
414 | ret = true; | 424 | ret = true; |
415 | haveShape = true; | 425 | haveShape = true; |
416 | } | 426 | } |
417 | 427 | ||
418 | // Compound shapes are handled special as they are rebuilt from scratch. | 428 | // Compound shapes are handled special as they are rebuilt from scratch. |
419 | // This isn't too great a hardship since most of the child shapes will already been created. | 429 | // This isn't too great a hardship since most of the child shapes will have already been created. |
420 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) | 430 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) |
421 | { | 431 | { |
422 | ret = GetReferenceToCompoundShape(prim, shapeCallback); | 432 | ret = GetReferenceToCompoundShape(prim, shapeCallback); |
423 | DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); | 433 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); |
424 | haveShape = true; | 434 | haveShape = true; |
425 | } | 435 | } |
426 | 436 | ||
@@ -433,7 +443,7 @@ public sealed class BSShapeCollection : IDisposable | |||
433 | } | 443 | } |
434 | 444 | ||
435 | // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. | 445 | // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. |
436 | private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 446 | public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) |
437 | { | 447 | { |
438 | bool ret = false; | 448 | bool ret = false; |
439 | bool haveShape = false; | 449 | bool haveShape = false; |
@@ -443,8 +453,9 @@ public sealed class BSShapeCollection : IDisposable | |||
443 | // If the prim attributes are simple, this could be a simple Bullet native shape | 453 | // If the prim attributes are simple, this could be a simple Bullet native shape |
444 | if (!haveShape | 454 | if (!haveShape |
445 | && pbs != null | 455 | && pbs != null |
456 | && !pbs.SculptEntry | ||
446 | && nativeShapePossible | 457 | && nativeShapePossible |
447 | && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) | 458 | && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) |
448 | || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | 459 | || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 |
449 | && pbs.ProfileHollow == 0 | 460 | && pbs.ProfileHollow == 0 |
450 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | 461 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 |
@@ -453,19 +464,27 @@ public sealed class BSShapeCollection : IDisposable | |||
453 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | 464 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 |
454 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) | 465 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) |
455 | { | 466 | { |
467 | // Get the scale of any existing shape so we can see if the new shape is same native type and same size. | ||
468 | OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; | ||
469 | if (prim.PhysShape.HasPhysicalShape) | ||
470 | scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape); | ||
471 | |||
472 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", | ||
473 | prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); | ||
474 | |||
456 | // It doesn't look like Bullet scales spheres so make sure the scales are all equal | 475 | // It doesn't look like Bullet scales spheres so make sure the scales are all equal |
457 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | 476 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) |
458 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) | 477 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) |
459 | { | 478 | { |
460 | haveShape = true; | 479 | haveShape = true; |
461 | if (forceRebuild | 480 | if (forceRebuild |
462 | || prim.Scale != prim.Size | 481 | || prim.Scale != scaleOfExistingShape |
463 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE | 482 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE |
464 | ) | 483 | ) |
465 | { | 484 | { |
466 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, | 485 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, |
467 | FixedShapeKey.KEY_SPHERE, shapeCallback); | 486 | FixedShapeKey.KEY_SPHERE, shapeCallback); |
468 | DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", | 487 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", |
469 | prim.LocalID, forceRebuild, prim.PhysShape); | 488 | prim.LocalID, forceRebuild, prim.PhysShape); |
470 | } | 489 | } |
471 | } | 490 | } |
@@ -473,13 +492,13 @@ public sealed class BSShapeCollection : IDisposable | |||
473 | { | 492 | { |
474 | haveShape = true; | 493 | haveShape = true; |
475 | if (forceRebuild | 494 | if (forceRebuild |
476 | || prim.Scale != prim.Size | 495 | || prim.Scale != scaleOfExistingShape |
477 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX | 496 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX |
478 | ) | 497 | ) |
479 | { | 498 | { |
480 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, | 499 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, |
481 | FixedShapeKey.KEY_BOX, shapeCallback); | 500 | FixedShapeKey.KEY_BOX, shapeCallback); |
482 | DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", | 501 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", |
483 | prim.LocalID, forceRebuild, prim.PhysShape); | 502 | prim.LocalID, forceRebuild, prim.PhysShape); |
484 | } | 503 | } |
485 | } | 504 | } |
@@ -500,17 +519,17 @@ public sealed class BSShapeCollection : IDisposable | |||
500 | bool ret = false; | 519 | bool ret = false; |
501 | // Note that if it's a native shape, the check for physical/non-physical is not | 520 | // Note that if it's a native shape, the check for physical/non-physical is not |
502 | // made. Native shapes work in either case. | 521 | // made. Native shapes work in either case. |
503 | if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) | 522 | if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) |
504 | { | 523 | { |
505 | // Update prim.BSShape to reference a hull of this shape. | 524 | // Update prim.BSShape to reference a hull of this shape. |
506 | ret = GetReferenceToHull(prim,shapeCallback); | 525 | ret = GetReferenceToHull(prim,shapeCallback); |
507 | DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", | 526 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", |
508 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | 527 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); |
509 | } | 528 | } |
510 | else | 529 | else |
511 | { | 530 | { |
512 | ret = GetReferenceToMesh(prim, shapeCallback); | 531 | ret = GetReferenceToMesh(prim, shapeCallback); |
513 | DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", | 532 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", |
514 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | 533 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); |
515 | } | 534 | } |
516 | return ret; | 535 | return ret; |
@@ -528,9 +547,10 @@ public sealed class BSShapeCollection : IDisposable | |||
528 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); | 547 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); |
529 | 548 | ||
530 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. | 549 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. |
531 | DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", | 550 | if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", |
532 | prim.LocalID, newShape, prim.Scale); | 551 | prim.LocalID, newShape, prim.Scale); |
533 | 552 | ||
553 | // native shapes are scaled by Bullet | ||
534 | prim.PhysShape = newShape; | 554 | prim.PhysShape = newShape; |
535 | return true; | 555 | return true; |
536 | } | 556 | } |
@@ -550,20 +570,17 @@ public sealed class BSShapeCollection : IDisposable | |||
550 | 570 | ||
551 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) | 571 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) |
552 | { | 572 | { |
553 | // The proper scale has been calculated in the prim. | 573 | |
554 | newShape = new BulletShape( | 574 | newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale); |
555 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) | 575 | if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); |
556 | , shapeType); | ||
557 | DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | ||
558 | } | 576 | } |
559 | else | 577 | else |
560 | { | 578 | { |
561 | // Native shapes are scaled in Bullet so set the scaling to the size | 579 | // Native shapes are scaled in Bullet so set the scaling to the size |
562 | prim.Scale = prim.Size; | 580 | newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData); |
563 | nativeShapeData.Scale = prim.Scale; | 581 | |
564 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); | ||
565 | } | 582 | } |
566 | if (newShape.ptr == IntPtr.Zero) | 583 | if (!newShape.HasPhysicalShape) |
567 | { | 584 | { |
568 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | 585 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", |
569 | LogHeader, prim.LocalID, shapeType); | 586 | LogHeader, prim.LocalID, shapeType); |
@@ -580,7 +597,7 @@ public sealed class BSShapeCollection : IDisposable | |||
580 | // Called at taint-time! | 597 | // Called at taint-time! |
581 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 598 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) |
582 | { | 599 | { |
583 | BulletShape newShape = new BulletShape(IntPtr.Zero); | 600 | BulletShape newShape = new BulletShape(); |
584 | 601 | ||
585 | float lod; | 602 | float lod; |
586 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | 603 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); |
@@ -589,7 +606,7 @@ public sealed class BSShapeCollection : IDisposable | |||
589 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) | 606 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) |
590 | return false; | 607 | return false; |
591 | 608 | ||
592 | DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", | 609 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", |
593 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); | 610 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); |
594 | 611 | ||
595 | // Since we're recreating new, get rid of the reference to the previous shape | 612 | // Since we're recreating new, get rid of the reference to the previous shape |
@@ -601,8 +618,6 @@ public sealed class BSShapeCollection : IDisposable | |||
601 | 618 | ||
602 | ReferenceShape(newShape); | 619 | ReferenceShape(newShape); |
603 | 620 | ||
604 | // meshes are already scaled by the meshmerizer | ||
605 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | ||
606 | prim.PhysShape = newShape; | 621 | prim.PhysShape = newShape; |
607 | 622 | ||
608 | return true; // 'true' means a new shape has been added to this prim | 623 | return true; // 'true' means a new shape has been added to this prim |
@@ -610,18 +625,18 @@ public sealed class BSShapeCollection : IDisposable | |||
610 | 625 | ||
611 | private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 626 | private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) |
612 | { | 627 | { |
628 | BulletShape newShape = new BulletShape(); | ||
613 | IMesh meshData = null; | 629 | IMesh meshData = null; |
614 | IntPtr meshPtr = IntPtr.Zero; | 630 | |
615 | MeshDesc meshDesc; | 631 | MeshDesc meshDesc; |
616 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) | 632 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) |
617 | { | 633 | { |
618 | // If the mesh has already been built just use it. | 634 | // If the mesh has already been built just use it. |
619 | meshPtr = meshDesc.ptr; | 635 | newShape = meshDesc.shape.Clone(); |
620 | } | 636 | } |
621 | else | 637 | else |
622 | { | 638 | { |
623 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 639 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); |
624 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | ||
625 | 640 | ||
626 | if (meshData != null) | 641 | if (meshData != null) |
627 | { | 642 | { |
@@ -640,11 +655,10 @@ public sealed class BSShapeCollection : IDisposable | |||
640 | // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | 655 | // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", |
641 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); | 656 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); |
642 | 657 | ||
643 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | 658 | newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, |
644 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); | 659 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); |
645 | } | 660 | } |
646 | } | 661 | } |
647 | BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH); | ||
648 | newShape.shapeKey = newMeshKey; | 662 | newShape.shapeKey = newMeshKey; |
649 | 663 | ||
650 | return newShape; | 664 | return newShape; |
@@ -663,7 +677,7 @@ public sealed class BSShapeCollection : IDisposable | |||
663 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) | 677 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) |
664 | return false; | 678 | return false; |
665 | 679 | ||
666 | DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", | 680 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", |
667 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); | 681 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); |
668 | 682 | ||
669 | // Remove usage of the previous shape. | 683 | // Remove usage of the previous shape. |
@@ -674,8 +688,6 @@ public sealed class BSShapeCollection : IDisposable | |||
674 | 688 | ||
675 | ReferenceShape(newShape); | 689 | ReferenceShape(newShape); |
676 | 690 | ||
677 | // hulls are already scaled by the meshmerizer | ||
678 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | ||
679 | prim.PhysShape = newShape; | 691 | prim.PhysShape = newShape; |
680 | return true; // 'true' means a new shape has been added to this prim | 692 | return true; // 'true' means a new shape has been added to this prim |
681 | } | 693 | } |
@@ -684,18 +696,20 @@ public sealed class BSShapeCollection : IDisposable | |||
684 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 696 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) |
685 | { | 697 | { |
686 | 698 | ||
699 | BulletShape newShape = new BulletShape(); | ||
687 | IntPtr hullPtr = IntPtr.Zero; | 700 | IntPtr hullPtr = IntPtr.Zero; |
701 | |||
688 | HullDesc hullDesc; | 702 | HullDesc hullDesc; |
689 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) | 703 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) |
690 | { | 704 | { |
691 | // If the hull shape already is created, just use it. | 705 | // If the hull shape already is created, just use it. |
692 | hullPtr = hullDesc.ptr; | 706 | newShape = hullDesc.shape.Clone(); |
693 | } | 707 | } |
694 | else | 708 | else |
695 | { | 709 | { |
696 | // Build a new hull in the physical world | 710 | // Build a new hull in the physical world |
697 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 711 | // Pass true for physicalness as this creates some sort of bounding box which we don't need |
698 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | 712 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); |
699 | if (meshData != null) | 713 | if (meshData != null) |
700 | { | 714 | { |
701 | 715 | ||
@@ -777,14 +791,13 @@ public sealed class BSShapeCollection : IDisposable | |||
777 | } | 791 | } |
778 | } | 792 | } |
779 | // create the hull data structure in Bullet | 793 | // create the hull data structure in Bullet |
780 | hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); | 794 | newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls); |
781 | } | 795 | } |
782 | } | 796 | } |
783 | 797 | ||
784 | BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL); | ||
785 | newShape.shapeKey = newHullKey; | 798 | newShape.shapeKey = newHullKey; |
786 | 799 | ||
787 | return newShape; // 'true' means a new shape has been added to this prim | 800 | return newShape; |
788 | } | 801 | } |
789 | 802 | ||
790 | // Callback from convex hull creater with a newly created hull. | 803 | // Callback from convex hull creater with a newly created hull. |
@@ -803,13 +816,13 @@ public sealed class BSShapeCollection : IDisposable | |||
803 | // Don't need to do this as the shape is freed when the new root shape is created below. | 816 | // Don't need to do this as the shape is freed when the new root shape is created below. |
804 | // DereferenceShape(prim.PhysShape, true, shapeCallback); | 817 | // DereferenceShape(prim.PhysShape, true, shapeCallback); |
805 | 818 | ||
806 | BulletShape cShape = new BulletShape( | 819 | |
807 | BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND); | 820 | BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false); |
808 | 821 | ||
809 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. | 822 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. |
810 | CreateGeomMeshOrHull(prim, shapeCallback); | 823 | CreateGeomMeshOrHull(prim, shapeCallback); |
811 | BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); | 824 | PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity); |
812 | DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", | 825 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", |
813 | prim.LocalID, cShape, prim.PhysShape); | 826 | prim.LocalID, cShape, prim.PhysShape); |
814 | 827 | ||
815 | prim.PhysShape = cShape; | 828 | prim.PhysShape = cShape; |
@@ -822,14 +835,14 @@ public sealed class BSShapeCollection : IDisposable | |||
822 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) | 835 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) |
823 | { | 836 | { |
824 | // level of detail based on size and type of the object | 837 | // level of detail based on size and type of the object |
825 | float lod = PhysicsScene.MeshLOD; | 838 | float lod = BSParam.MeshLOD; |
826 | if (pbs.SculptEntry) | 839 | if (pbs.SculptEntry) |
827 | lod = PhysicsScene.SculptLOD; | 840 | lod = BSParam.SculptLOD; |
828 | 841 | ||
829 | // Mega prims usually get more detail because one can interact with shape approximations at this size. | 842 | // Mega prims usually get more detail because one can interact with shape approximations at this size. |
830 | float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); | 843 | float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); |
831 | if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) | 844 | if (maxAxis > BSParam.MeshMegaPrimThreshold) |
832 | lod = PhysicsScene.MeshMegaPrimLOD; | 845 | lod = BSParam.MeshMegaPrimLOD; |
833 | 846 | ||
834 | retLod = lod; | 847 | retLod = lod; |
835 | return pbs.GetMeshKey(size, lod); | 848 | return pbs.GetMeshKey(size, lod); |
@@ -851,7 +864,7 @@ public sealed class BSShapeCollection : IDisposable | |||
851 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) | 864 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) |
852 | { | 865 | { |
853 | // If the shape was successfully created, nothing more to do | 866 | // If the shape was successfully created, nothing more to do |
854 | if (newShape.ptr != IntPtr.Zero) | 867 | if (newShape.HasPhysicalShape) |
855 | return newShape; | 868 | return newShape; |
856 | 869 | ||
857 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | 870 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset |
@@ -904,19 +917,19 @@ public sealed class BSShapeCollection : IDisposable | |||
904 | // Updates prim.BSBody with the information about the new body if one is created. | 917 | // Updates prim.BSBody with the information about the new body if one is created. |
905 | // Returns 'true' if an object was actually created. | 918 | // Returns 'true' if an object was actually created. |
906 | // Called at taint-time. | 919 | // Called at taint-time. |
907 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, | 920 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BulletShape shape, |
908 | BodyDestructionCallback bodyCallback) | 921 | BodyDestructionCallback bodyCallback) |
909 | { | 922 | { |
910 | bool ret = false; | 923 | bool ret = false; |
911 | 924 | ||
912 | // the mesh, hull or native shape must have already been created in Bullet | 925 | // the mesh, hull or native shape must have already been created in Bullet |
913 | bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); | 926 | bool mustRebuild = !prim.PhysBody.HasPhysicalBody; |
914 | 927 | ||
915 | // If there is an existing body, verify it's of an acceptable type. | 928 | // If there is an existing body, verify it's of an acceptable type. |
916 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. | 929 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. |
917 | if (!mustRebuild) | 930 | if (!mustRebuild) |
918 | { | 931 | { |
919 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr); | 932 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody); |
920 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY | 933 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY |
921 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) | 934 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) |
922 | { | 935 | { |
@@ -931,20 +944,16 @@ public sealed class BSShapeCollection : IDisposable | |||
931 | DereferenceBody(prim.PhysBody, true, bodyCallback); | 944 | DereferenceBody(prim.PhysBody, true, bodyCallback); |
932 | 945 | ||
933 | BulletBody aBody; | 946 | BulletBody aBody; |
934 | IntPtr bodyPtr = IntPtr.Zero; | ||
935 | if (prim.IsSolid) | 947 | if (prim.IsSolid) |
936 | { | 948 | { |
937 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, | 949 | aBody = PhysicsScene.PE.CreateBodyFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation); |
938 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | 950 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody); |
939 | DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | ||
940 | } | 951 | } |
941 | else | 952 | else |
942 | { | 953 | { |
943 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, | 954 | aBody = PhysicsScene.PE.CreateGhostFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation); |
944 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | 955 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); |
945 | DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | ||
946 | } | 956 | } |
947 | aBody = new BulletBody(prim.LocalID, bodyPtr); | ||
948 | 957 | ||
949 | ReferenceBody(aBody, true); | 958 | ReferenceBody(aBody, true); |
950 | 959 | ||
@@ -956,13 +965,13 @@ public sealed class BSShapeCollection : IDisposable | |||
956 | return ret; | 965 | return ret; |
957 | } | 966 | } |
958 | 967 | ||
959 | private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc) | 968 | private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc) |
960 | { | 969 | { |
961 | bool ret = false; | 970 | bool ret = false; |
962 | MeshDesc foundDesc = new MeshDesc(); | 971 | MeshDesc foundDesc = new MeshDesc(); |
963 | foreach (MeshDesc md in Meshes.Values) | 972 | foreach (MeshDesc md in Meshes.Values) |
964 | { | 973 | { |
965 | if (md.ptr == addr) | 974 | if (md.shape.ReferenceSame(shape)) |
966 | { | 975 | { |
967 | foundDesc = md; | 976 | foundDesc = md; |
968 | ret = true; | 977 | ret = true; |
@@ -974,13 +983,13 @@ public sealed class BSShapeCollection : IDisposable | |||
974 | return ret; | 983 | return ret; |
975 | } | 984 | } |
976 | 985 | ||
977 | private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc) | 986 | private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc) |
978 | { | 987 | { |
979 | bool ret = false; | 988 | bool ret = false; |
980 | HullDesc foundDesc = new HullDesc(); | 989 | HullDesc foundDesc = new HullDesc(); |
981 | foreach (HullDesc hd in Hulls.Values) | 990 | foreach (HullDesc hd in Hulls.Values) |
982 | { | 991 | { |
983 | if (hd.ptr == addr) | 992 | if (hd.shape.ReferenceSame(shape)) |
984 | { | 993 | { |
985 | foundDesc = hd; | 994 | foundDesc = hd; |
986 | ret = true; | 995 | ret = true; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 96cd55e..c75eb9b 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | |||
@@ -91,11 +91,17 @@ public abstract class BSShape | |||
91 | // All shapes have a static call to get a reference to the physical shape | 91 | // All shapes have a static call to get a reference to the physical shape |
92 | // protected abstract static BSShape GetReference(); | 92 | // protected abstract static BSShape GetReference(); |
93 | 93 | ||
94 | // Returns a string for debugging that uniquily identifies the memory used by this instance | ||
95 | public string AddrString | ||
96 | { | ||
97 | get { return ptr.ToString("X"); } | ||
98 | } | ||
99 | |||
94 | public override string ToString() | 100 | public override string ToString() |
95 | { | 101 | { |
96 | StringBuilder buff = new StringBuilder(); | 102 | StringBuilder buff = new StringBuilder(); |
97 | buff.Append("<p="); | 103 | buff.Append("<p="); |
98 | buff.Append(ptr.ToString("X")); | 104 | buff.Append(AddrString); |
99 | buff.Append(",s="); | 105 | buff.Append(",s="); |
100 | buff.Append(type.ToString()); | 106 | buff.Append(type.ToString()); |
101 | buff.Append(",k="); | 107 | buff.Append(",k="); |
@@ -126,7 +132,8 @@ public class BSShapeNative : BSShape | |||
126 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | 132 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) |
127 | { | 133 | { |
128 | // Native shapes are not shared and are always built anew. | 134 | // Native shapes are not shared and are always built anew. |
129 | return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); | 135 | //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); |
136 | return null; | ||
130 | } | 137 | } |
131 | 138 | ||
132 | private BSShapeNative(BSScene physicsScene, BSPhysObject prim, | 139 | private BSShapeNative(BSScene physicsScene, BSPhysObject prim, |
@@ -141,14 +148,15 @@ public class BSShapeNative : BSShape | |||
141 | nativeShapeData.HullKey = (ulong)shapeKey; | 148 | nativeShapeData.HullKey = (ulong)shapeKey; |
142 | 149 | ||
143 | 150 | ||
151 | /* | ||
144 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) | 152 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) |
145 | { | 153 | { |
146 | ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale); | 154 | ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); |
147 | physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | 155 | physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); |
148 | } | 156 | } |
149 | else | 157 | else |
150 | { | 158 | { |
151 | ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData); | 159 | ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); |
152 | } | 160 | } |
153 | if (ptr == IntPtr.Zero) | 161 | if (ptr == IntPtr.Zero) |
154 | { | 162 | { |
@@ -157,15 +165,18 @@ public class BSShapeNative : BSShape | |||
157 | } | 165 | } |
158 | type = shapeType; | 166 | type = shapeType; |
159 | key = (UInt64)shapeKey; | 167 | key = (UInt64)shapeKey; |
168 | */ | ||
160 | } | 169 | } |
161 | // Make this reference to the physical shape go away since native shapes are not shared. | 170 | // Make this reference to the physical shape go away since native shapes are not shared. |
162 | public override void Dereference(BSScene physicsScene) | 171 | public override void Dereference(BSScene physicsScene) |
163 | { | 172 | { |
173 | /* | ||
164 | // Native shapes are not tracked and are released immediately | 174 | // Native shapes are not tracked and are released immediately |
165 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); | 175 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); |
166 | BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr); | 176 | PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this); |
167 | ptr = IntPtr.Zero; | 177 | ptr = IntPtr.Zero; |
168 | // Garbage collection will free up this instance. | 178 | // Garbage collection will free up this instance. |
179 | */ | ||
169 | } | 180 | } |
170 | } | 181 | } |
171 | 182 | ||
@@ -205,4 +216,17 @@ public class BSShapeCompound : BSShape | |||
205 | } | 216 | } |
206 | public override void Dereference(BSScene physicsScene) { } | 217 | public override void Dereference(BSScene physicsScene) { } |
207 | } | 218 | } |
219 | |||
220 | public class BSShapeAvatar : BSShape | ||
221 | { | ||
222 | private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; | ||
223 | public BSShapeAvatar() : base() | ||
224 | { | ||
225 | } | ||
226 | public static BSShape GetReference(BSPhysObject prim) | ||
227 | { | ||
228 | return new BSShapeNull(); | ||
229 | } | ||
230 | public override void Dereference(BSScene physicsScene) { } | ||
231 | } | ||
208 | } | 232 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs index 3ca756c..e4fecc3 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs | |||
@@ -44,7 +44,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
44 | { | 44 | { |
45 | static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]"; | 45 | static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]"; |
46 | 46 | ||
47 | BulletHeightMapInfo m_mapInfo = null; | 47 | BulletHMapInfo m_mapInfo = null; |
48 | 48 | ||
49 | // Constructor to build a default, flat heightmap terrain. | 49 | // Constructor to build a default, flat heightmap terrain. |
50 | public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) | 50 | public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) |
@@ -58,7 +58,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
58 | { | 58 | { |
59 | initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; | 59 | initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; |
60 | } | 60 | } |
61 | m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero); | 61 | m_mapInfo = new BulletHMapInfo(id, initialMap); |
62 | m_mapInfo.minCoords = minTerrainCoords; | 62 | m_mapInfo.minCoords = minTerrainCoords; |
63 | m_mapInfo.maxCoords = maxTerrainCoords; | 63 | m_mapInfo.maxCoords = maxTerrainCoords; |
64 | m_mapInfo.terrainRegionBase = TerrainBase; | 64 | m_mapInfo.terrainRegionBase = TerrainBase; |
@@ -72,7 +72,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
72 | Vector3 minCoords, Vector3 maxCoords) | 72 | Vector3 minCoords, Vector3 maxCoords) |
73 | : base(physicsScene, regionBase, id) | 73 | : base(physicsScene, regionBase, id) |
74 | { | 74 | { |
75 | m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero); | 75 | m_mapInfo = new BulletHMapInfo(id, initialMap); |
76 | m_mapInfo.minCoords = minCoords; | 76 | m_mapInfo.minCoords = minCoords; |
77 | m_mapInfo.maxCoords = maxCoords; | 77 | m_mapInfo.maxCoords = maxCoords; |
78 | m_mapInfo.minZ = minCoords.Z; | 78 | m_mapInfo.minZ = minCoords.Z; |
@@ -91,13 +91,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
91 | // Using the information in m_mapInfo, create the physical representation of the heightmap. | 91 | // Using the information in m_mapInfo, create the physical representation of the heightmap. |
92 | private void BuildHeightmapTerrain() | 92 | private void BuildHeightmapTerrain() |
93 | { | 93 | { |
94 | m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, | ||
95 | m_mapInfo.minCoords, m_mapInfo.maxCoords, | ||
96 | m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN); | ||
97 | |||
98 | // Create the terrain shape from the mapInfo | 94 | // Create the terrain shape from the mapInfo |
99 | m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), | 95 | m_mapInfo.terrainShape = PhysicsScene.PE.CreateTerrainShape( m_mapInfo.ID, |
100 | BSPhysicsShapeType.SHAPE_TERRAIN); | 96 | new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ, |
97 | m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); | ||
98 | |||
101 | 99 | ||
102 | // The terrain object initial position is at the center of the object | 100 | // The terrain object initial position is at the center of the object |
103 | Vector3 centerPos; | 101 | Vector3 centerPos; |
@@ -105,28 +103,26 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
105 | centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); | 103 | centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); |
106 | centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); | 104 | centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); |
107 | 105 | ||
108 | m_mapInfo.terrainBody = new BulletBody(m_mapInfo.ID, | 106 | m_mapInfo.terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, |
109 | BulletSimAPI.CreateBodyWithDefaultMotionState2(m_mapInfo.terrainShape.ptr, | 107 | m_mapInfo.ID, centerPos, Quaternion.Identity); |
110 | m_mapInfo.ID, centerPos, Quaternion.Identity)); | ||
111 | 108 | ||
112 | // Set current terrain attributes | 109 | // Set current terrain attributes |
113 | BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction); | 110 | PhysicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); |
114 | BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); | 111 | PhysicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); |
115 | BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution); | 112 | PhysicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); |
116 | BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 113 | PhysicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); |
117 | 114 | ||
118 | // Return the new terrain to the world of physical objects | 115 | // Return the new terrain to the world of physical objects |
119 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | 116 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody); |
120 | 117 | ||
121 | // redo its bounding box now that it is in the world | 118 | // redo its bounding box now that it is in the world |
122 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | 119 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody); |
123 | 120 | ||
124 | BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr, | 121 | m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; |
125 | (uint)CollisionFilterGroups.TerrainFilter, | 122 | m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene); |
126 | (uint)CollisionFilterGroups.TerrainMask); | ||
127 | 123 | ||
128 | // Make it so the terrain will not move or be considered for movement. | 124 | // Make it so the terrain will not move or be considered for movement. |
129 | BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | 125 | PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); |
130 | 126 | ||
131 | return; | 127 | return; |
132 | } | 128 | } |
@@ -136,19 +132,18 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
136 | { | 132 | { |
137 | if (m_mapInfo != null) | 133 | if (m_mapInfo != null) |
138 | { | 134 | { |
139 | if (m_mapInfo.terrainBody.ptr != IntPtr.Zero) | 135 | if (m_mapInfo.terrainBody.HasPhysicalBody) |
140 | { | 136 | { |
141 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | 137 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody); |
142 | // Frees both the body and the shape. | 138 | // Frees both the body and the shape. |
143 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | 139 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody); |
144 | BulletSimAPI.ReleaseHeightMapInfo2(m_mapInfo.Ptr); | ||
145 | } | 140 | } |
146 | } | 141 | } |
147 | m_mapInfo = null; | 142 | m_mapInfo = null; |
148 | } | 143 | } |
149 | 144 | ||
150 | // The passed position is relative to the base of the region. | 145 | // The passed position is relative to the base of the region. |
151 | public override float GetHeightAtXYZ(Vector3 pos) | 146 | public override float GetTerrainHeightAtXYZ(Vector3 pos) |
152 | { | 147 | { |
153 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | 148 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; |
154 | 149 | ||
@@ -166,5 +161,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
166 | } | 161 | } |
167 | return ret; | 162 | return ret; |
168 | } | 163 | } |
164 | |||
165 | // The passed position is relative to the base of the region. | ||
166 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
167 | { | ||
168 | return PhysicsScene.SimpleWaterLevel; | ||
169 | } | ||
169 | } | 170 | } |
170 | } | 171 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 23fcfd3..2e9db39 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | |||
@@ -62,11 +62,12 @@ public abstract class BSTerrainPhys : IDisposable | |||
62 | ID = id; | 62 | ID = id; |
63 | } | 63 | } |
64 | public abstract void Dispose(); | 64 | public abstract void Dispose(); |
65 | public abstract float GetHeightAtXYZ(Vector3 pos); | 65 | public abstract float GetTerrainHeightAtXYZ(Vector3 pos); |
66 | public abstract float GetWaterLevelAtXYZ(Vector3 pos); | ||
66 | } | 67 | } |
67 | 68 | ||
68 | // ========================================================================================== | 69 | // ========================================================================================== |
69 | public sealed class BSTerrainManager | 70 | public sealed class BSTerrainManager : IDisposable |
70 | { | 71 | { |
71 | static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; | 72 | static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; |
72 | 73 | ||
@@ -75,13 +76,12 @@ public sealed class BSTerrainManager | |||
75 | public const float HEIGHT_INITIALIZATION = 24.987f; | 76 | public const float HEIGHT_INITIALIZATION = 24.987f; |
76 | public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; | 77 | public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; |
77 | public const float HEIGHT_GETHEIGHT_RET = 24.765f; | 78 | public const float HEIGHT_GETHEIGHT_RET = 24.765f; |
79 | public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f; | ||
78 | 80 | ||
79 | // If the min and max height are equal, we reduce the min by this | 81 | // If the min and max height are equal, we reduce the min by this |
80 | // amount to make sure that a bounding box is built for the terrain. | 82 | // amount to make sure that a bounding box is built for the terrain. |
81 | public const float HEIGHT_EQUAL_FUDGE = 0.2f; | 83 | public const float HEIGHT_EQUAL_FUDGE = 0.2f; |
82 | 84 | ||
83 | public const float TERRAIN_COLLISION_MARGIN = 0.0f; | ||
84 | |||
85 | // Until the whole simulator is changed to pass us the region size, we rely on constants. | 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); | 86 | public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); |
87 | 87 | ||
@@ -122,25 +122,28 @@ public sealed class BSTerrainManager | |||
122 | MegaRegionParentPhysicsScene = null; | 122 | MegaRegionParentPhysicsScene = null; |
123 | } | 123 | } |
124 | 124 | ||
125 | public void Dispose() | ||
126 | { | ||
127 | ReleaseGroundPlaneAndTerrain(); | ||
128 | } | ||
129 | |||
125 | // Create the initial instance of terrain and the underlying ground plane. | 130 | // Create the initial instance of terrain and the underlying ground plane. |
126 | // This is called from the initialization routine so we presume it is | 131 | // This is called from the initialization routine so we presume it is |
127 | // safe to call Bullet in real time. We hope no one is moving prims around yet. | 132 | // safe to call Bullet in real time. We hope no one is moving prims around yet. |
128 | public void CreateInitialGroundPlaneAndTerrain() | 133 | public void CreateInitialGroundPlaneAndTerrain() |
129 | { | 134 | { |
130 | // The ground plane is here to catch things that are trying to drop to negative infinity | 135 | // The ground plane is here to catch things that are trying to drop to negative infinity |
131 | BulletShape groundPlaneShape = new BulletShape( | 136 | BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); |
132 | BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), | 137 | m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, |
133 | BSPhysicsShapeType.SHAPE_GROUNDPLANE); | 138 | BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); |
134 | m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, | 139 | |
135 | BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, | 140 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane); |
136 | Vector3.Zero, Quaternion.Identity)); | 141 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane); |
137 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr); | ||
138 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr); | ||
139 | // Ground plane does not move | 142 | // Ground plane does not move |
140 | BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); | 143 | PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); |
141 | // Everything collides with the ground plane. | 144 | // Everything collides with the ground plane. |
142 | BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, | 145 | m_groundPlane.collisionType = CollisionType.Groundplane; |
143 | (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); | 146 | m_groundPlane.ApplyCollisionMask(PhysicsScene); |
144 | 147 | ||
145 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. | 148 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. |
146 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); | 149 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); |
@@ -150,13 +153,13 @@ public sealed class BSTerrainManager | |||
150 | // Release all the terrain structures we might have allocated | 153 | // Release all the terrain structures we might have allocated |
151 | public void ReleaseGroundPlaneAndTerrain() | 154 | public void ReleaseGroundPlaneAndTerrain() |
152 | { | 155 | { |
153 | if (m_groundPlane.ptr != IntPtr.Zero) | 156 | if (m_groundPlane.HasPhysicalBody) |
154 | { | 157 | { |
155 | if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) | 158 | if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) |
156 | { | 159 | { |
157 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); | 160 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane); |
158 | } | 161 | } |
159 | m_groundPlane.ptr = IntPtr.Zero; | 162 | m_groundPlane.Clear(); |
160 | } | 163 | } |
161 | 164 | ||
162 | ReleaseTerrain(); | 165 | ReleaseTerrain(); |
@@ -165,17 +168,22 @@ public sealed class BSTerrainManager | |||
165 | // Release all the terrain we have allocated | 168 | // Release all the terrain we have allocated |
166 | public void ReleaseTerrain() | 169 | public void ReleaseTerrain() |
167 | { | 170 | { |
168 | foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) | 171 | lock (m_terrains) |
169 | { | 172 | { |
170 | kvp.Value.Dispose(); | 173 | foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) |
174 | { | ||
175 | kvp.Value.Dispose(); | ||
176 | } | ||
177 | m_terrains.Clear(); | ||
171 | } | 178 | } |
172 | m_terrains.Clear(); | ||
173 | } | 179 | } |
174 | 180 | ||
175 | // The simulator wants to set a new heightmap for the terrain. | 181 | // The simulator wants to set a new heightmap for the terrain. |
176 | public void SetTerrain(float[] heightMap) { | 182 | public void SetTerrain(float[] heightMap) { |
177 | float[] localHeightMap = heightMap; | 183 | float[] localHeightMap = heightMap; |
178 | PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() | 184 | // If there are multiple requests for changes to the same terrain between ticks, |
185 | // only do that last one. | ||
186 | PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() | ||
179 | { | 187 | { |
180 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) | 188 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) |
181 | { | 189 | { |
@@ -211,6 +219,7 @@ public sealed class BSTerrainManager | |||
211 | // terrain shape is created and added to the body. | 219 | // terrain shape is created and added to the body. |
212 | // This call is most often used to update the heightMap and parameters of the terrain. | 220 | // This call is most often used to update the heightMap and parameters of the terrain. |
213 | // (The above does suggest that some simplification/refactoring is in order.) | 221 | // (The above does suggest that some simplification/refactoring is in order.) |
222 | // Called during taint-time. | ||
214 | private void UpdateTerrain(uint id, float[] heightMap, | 223 | private void UpdateTerrain(uint id, float[] heightMap, |
215 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) | 224 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) |
216 | { | 225 | { |
@@ -220,7 +229,7 @@ public sealed class BSTerrainManager | |||
220 | // Find high and low points of passed heightmap. | 229 | // Find high and low points of passed heightmap. |
221 | // The min and max passed in is usually the area objects can be in (maximum | 230 | // The min and max passed in is usually the area objects can be in (maximum |
222 | // object height, for instance). The terrain wants the bounding box for the | 231 | // object height, for instance). The terrain wants the bounding box for the |
223 | // terrain so we replace passed min and max Z with the actual terrain min/max Z. | 232 | // terrain so replace passed min and max Z with the actual terrain min/max Z. |
224 | float minZ = float.MaxValue; | 233 | float minZ = float.MaxValue; |
225 | float maxZ = float.MinValue; | 234 | float maxZ = float.MinValue; |
226 | foreach (float height in heightMap) | 235 | foreach (float height in heightMap) |
@@ -238,15 +247,15 @@ public sealed class BSTerrainManager | |||
238 | 247 | ||
239 | Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); | 248 | Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); |
240 | 249 | ||
241 | BSTerrainPhys terrainPhys; | 250 | lock (m_terrains) |
242 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) | ||
243 | { | 251 | { |
244 | // There is already a terrain in this spot. Free the old and build the new. | 252 | BSTerrainPhys terrainPhys; |
245 | DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", | 253 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) |
246 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); | ||
247 | |||
248 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate() | ||
249 | { | 254 | { |
255 | // There is already a terrain in this spot. Free the old and build the new. | ||
256 | DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", | ||
257 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); | ||
258 | |||
250 | // Remove old terrain from the collection | 259 | // Remove old terrain from the collection |
251 | m_terrains.Remove(terrainRegionBase); | 260 | m_terrains.Remove(terrainRegionBase); |
252 | // Release any physical memory it may be using. | 261 | // Release any physical memory it may be using. |
@@ -271,35 +280,24 @@ public sealed class BSTerrainManager | |||
271 | // I hate doing this, but just bail | 280 | // I hate doing this, but just bail |
272 | return; | 281 | return; |
273 | } | 282 | } |
274 | }); | 283 | } |
275 | } | 284 | else |
276 | else | 285 | { |
277 | { | 286 | // We don't know about this terrain so either we are creating a new terrain or |
278 | // We don't know about this terrain so either we are creating a new terrain or | 287 | // our mega-prim child is giving us a new terrain to add to the phys world |
279 | // our mega-prim child is giving us a new terrain to add to the phys world | ||
280 | |||
281 | // if this is a child terrain, calculate a unique terrain id | ||
282 | uint newTerrainID = id; | ||
283 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) | ||
284 | newTerrainID = ++m_terrainCount; | ||
285 | |||
286 | float[] heightMapX = heightMap; | ||
287 | Vector3 minCoordsX = minCoords; | ||
288 | Vector3 maxCoordsX = maxCoords; | ||
289 | 288 | ||
290 | DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", | 289 | // if this is a child terrain, calculate a unique terrain id |
291 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); | 290 | uint newTerrainID = id; |
291 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) | ||
292 | newTerrainID = ++m_terrainCount; | ||
292 | 293 | ||
293 | // Code that must happen at taint-time | 294 | DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", |
294 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() | 295 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); |
295 | { | ||
296 | DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}", | ||
297 | BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y); | ||
298 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | 296 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); |
299 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | 297 | m_terrains.Add(terrainRegionBase, newTerrainPhys); |
300 | 298 | ||
301 | m_terrainModified = true; | 299 | m_terrainModified = true; |
302 | }); | 300 | } |
303 | } | 301 | } |
304 | } | 302 | } |
305 | 303 | ||
@@ -308,9 +306,9 @@ public sealed class BSTerrainManager | |||
308 | { | 306 | { |
309 | PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", | 307 | PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", |
310 | LogHeader, PhysicsScene.RegionName, terrainRegionBase, | 308 | LogHeader, PhysicsScene.RegionName, terrainRegionBase, |
311 | (BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation); | 309 | (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); |
312 | BSTerrainPhys newTerrainPhys = null; | 310 | BSTerrainPhys newTerrainPhys = null; |
313 | switch ((int)PhysicsScene.Params.terrainImplementation) | 311 | switch ((int)BSParam.TerrainImplementation) |
314 | { | 312 | { |
315 | case (int)BSTerrainPhys.TerrainImplementation.Heightmap: | 313 | case (int)BSTerrainPhys.TerrainImplementation.Heightmap: |
316 | newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, | 314 | newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, |
@@ -323,14 +321,21 @@ public sealed class BSTerrainManager | |||
323 | default: | 321 | default: |
324 | PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", | 322 | PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", |
325 | LogHeader, | 323 | LogHeader, |
326 | (int)PhysicsScene.Params.terrainImplementation, | 324 | (int)BSParam.TerrainImplementation, |
327 | PhysicsScene.Params.terrainImplementation, | 325 | BSParam.TerrainImplementation, |
328 | PhysicsScene.RegionName, terrainRegionBase); | 326 | PhysicsScene.RegionName, terrainRegionBase); |
329 | break; | 327 | break; |
330 | } | 328 | } |
331 | return newTerrainPhys; | 329 | return newTerrainPhys; |
332 | } | 330 | } |
333 | 331 | ||
332 | // Return 'true' of this position is somewhere in known physical terrain space | ||
333 | public bool IsWithinKnownTerrain(Vector3 pos) | ||
334 | { | ||
335 | Vector3 terrainBaseXYZ; | ||
336 | BSTerrainPhys physTerrain; | ||
337 | return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); | ||
338 | } | ||
334 | 339 | ||
335 | // Given an X and Y, find the height of the terrain. | 340 | // Given an X and Y, find the height of the terrain. |
336 | // Since we could be handling multiple terrains for a mega-region, | 341 | // Since we could be handling multiple terrains for a mega-region, |
@@ -341,40 +346,74 @@ public sealed class BSTerrainManager | |||
341 | private float lastHeightTX = 999999f; | 346 | private float lastHeightTX = 999999f; |
342 | private float lastHeightTY = 999999f; | 347 | private float lastHeightTY = 999999f; |
343 | private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; | 348 | private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; |
344 | public float GetTerrainHeightAtXYZ(Vector3 loc) | 349 | public float GetTerrainHeightAtXYZ(Vector3 pos) |
345 | { | 350 | { |
346 | float tX = loc.X; | 351 | float tX = pos.X; |
347 | float tY = loc.Y; | 352 | float tY = pos.Y; |
348 | // You'd be surprized at the number of times this routine is called | 353 | // You'd be surprized at the number of times this routine is called |
349 | // with the same parameters as last time. | 354 | // with the same parameters as last time. |
350 | if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) | 355 | if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY)) |
351 | return lastHeight; | 356 | return lastHeight; |
357 | m_terrainModified = false; | ||
352 | 358 | ||
353 | lastHeightTX = tX; | 359 | lastHeightTX = tX; |
354 | lastHeightTY = tY; | 360 | lastHeightTY = tY; |
355 | float ret = HEIGHT_GETHEIGHT_RET; | 361 | float ret = HEIGHT_GETHEIGHT_RET; |
356 | 362 | ||
357 | int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | 363 | Vector3 terrainBaseXYZ; |
358 | int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
359 | Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | ||
360 | |||
361 | BSTerrainPhys physTerrain; | 364 | BSTerrainPhys physTerrain; |
362 | if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) | 365 | if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) |
363 | { | 366 | { |
364 | ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); | 367 | ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ); |
365 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}", | ||
366 | BSScene.DetailLogZero, loc, terrainBaseXYZ, ret); | ||
367 | } | 368 | } |
368 | else | 369 | else |
369 | { | 370 | { |
370 | PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", | 371 | PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", |
371 | LogHeader, PhysicsScene.RegionName, tX, tY); | 372 | LogHeader, PhysicsScene.RegionName, tX, tY); |
373 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", | ||
374 | BSScene.DetailLogZero, pos, terrainBaseXYZ); | ||
372 | } | 375 | } |
373 | m_terrainModified = false; | 376 | |
374 | lastHeight = ret; | 377 | lastHeight = ret; |
375 | return ret; | 378 | return ret; |
376 | } | 379 | } |
377 | 380 | ||
381 | public float GetWaterLevelAtXYZ(Vector3 pos) | ||
382 | { | ||
383 | float ret = WATER_HEIGHT_GETHEIGHT_RET; | ||
384 | |||
385 | Vector3 terrainBaseXYZ; | ||
386 | BSTerrainPhys physTerrain; | ||
387 | if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) | ||
388 | { | ||
389 | ret = physTerrain.GetWaterLevelAtXYZ(pos); | ||
390 | } | ||
391 | else | ||
392 | { | ||
393 | PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", | ||
394 | LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); | ||
395 | } | ||
396 | return ret; | ||
397 | } | ||
398 | |||
399 | // Given an address, return 'true' of there is a description of that terrain and output | ||
400 | // the descriptor class and the 'base' fo the addresses therein. | ||
401 | private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) | ||
402 | { | ||
403 | int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | ||
404 | int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
405 | Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | ||
406 | |||
407 | BSTerrainPhys physTerrain = null; | ||
408 | lock (m_terrains) | ||
409 | { | ||
410 | m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); | ||
411 | } | ||
412 | outTerrainBase = terrainBaseXYZ; | ||
413 | outPhysTerrain = physTerrain; | ||
414 | return (physTerrain != null); | ||
415 | } | ||
416 | |||
378 | // Although no one seems to check this, I do support combining. | 417 | // Although no one seems to check this, I do support combining. |
379 | public bool SupportsCombining() | 418 | public bool SupportsCombining() |
380 | { | 419 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index dca7150..1d55ce3 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs | |||
@@ -88,11 +88,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
88 | // Something is very messed up and a crash is in our future. | 88 | // Something is very messed up and a crash is in our future. |
89 | return; | 89 | return; |
90 | } | 90 | } |
91 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", | ||
92 | ID, indicesCount, indices.Length, verticesCount, vertices.Length); | ||
91 | 93 | ||
92 | m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | 94 | m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices); |
93 | indicesCount, indices, verticesCount, vertices), | 95 | if (!m_terrainShape.HasPhysicalShape) |
94 | BSPhysicsShapeType.SHAPE_MESH); | ||
95 | if (m_terrainShape.ptr == IntPtr.Zero) | ||
96 | { | 96 | { |
97 | // DISASTER!! | 97 | // DISASTER!! |
98 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); | 98 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); |
@@ -104,8 +104,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
104 | Vector3 pos = regionBase; | 104 | Vector3 pos = regionBase; |
105 | Quaternion rot = Quaternion.Identity; | 105 | Quaternion rot = Quaternion.Identity; |
106 | 106 | ||
107 | m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); | 107 | m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); |
108 | if (m_terrainBody.ptr == IntPtr.Zero) | 108 | if (!m_terrainBody.HasPhysicalBody) |
109 | { | 109 | { |
110 | // DISASTER!! | 110 | // DISASTER!! |
111 | physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); | 111 | physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); |
@@ -114,39 +114,38 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
114 | } | 114 | } |
115 | 115 | ||
116 | // Set current terrain attributes | 116 | // Set current terrain attributes |
117 | BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction); | 117 | PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); |
118 | BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); | 118 | PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); |
119 | BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution); | 119 | PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); |
120 | BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 120 | PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); |
121 | 121 | ||
122 | // Static objects are not very massive. | 122 | // Static objects are not very massive. |
123 | BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); | 123 | PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); |
124 | 124 | ||
125 | // Return the new terrain to the world of physical objects | 125 | // Put the new terrain to the world of physical objects |
126 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 126 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody); |
127 | 127 | ||
128 | // redo its bounding box now that it is in the world | 128 | // Redo its bounding box now that it is in the world |
129 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 129 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody); |
130 | 130 | ||
131 | BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, | 131 | m_terrainBody.collisionType = CollisionType.Terrain; |
132 | (uint)CollisionFilterGroups.TerrainFilter, | 132 | m_terrainBody.ApplyCollisionMask(PhysicsScene); |
133 | (uint)CollisionFilterGroups.TerrainMask); | ||
134 | 133 | ||
135 | // Make it so the terrain will not move or be considered for movement. | 134 | // Make it so the terrain will not move or be considered for movement. |
136 | BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | 135 | PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); |
137 | } | 136 | } |
138 | 137 | ||
139 | public override void Dispose() | 138 | public override void Dispose() |
140 | { | 139 | { |
141 | if (m_terrainBody.ptr != IntPtr.Zero) | 140 | if (m_terrainBody.HasPhysicalBody) |
142 | { | 141 | { |
143 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 142 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody); |
144 | // Frees both the body and the shape. | 143 | // Frees both the body and the shape. |
145 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 144 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody); |
146 | } | 145 | } |
147 | } | 146 | } |
148 | 147 | ||
149 | public override float GetHeightAtXYZ(Vector3 pos) | 148 | public override float GetTerrainHeightAtXYZ(Vector3 pos) |
150 | { | 149 | { |
151 | // For the moment use the saved heightmap to get the terrain height. | 150 | // For the moment use the saved heightmap to get the terrain height. |
152 | // TODO: raycast downward to find the true terrain below the position. | 151 | // TODO: raycast downward to find the true terrain below the position. |
@@ -167,6 +166,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
167 | return ret; | 166 | return ret; |
168 | } | 167 | } |
169 | 168 | ||
169 | // The passed position is relative to the base of the region. | ||
170 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
171 | { | ||
172 | return PhysicsScene.SimpleWaterLevel; | ||
173 | } | ||
174 | |||
170 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). | 175 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). |
171 | // Return 'true' if successfully created. | 176 | // Return 'true' if successfully created. |
172 | public static bool ConvertHeightmapToMesh( | 177 | public static bool ConvertHeightmapToMesh( |
@@ -188,6 +193,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
188 | // Simple mesh creation which assumes magnification == 1. | 193 | // Simple mesh creation which assumes magnification == 1. |
189 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. | 194 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. |
190 | 195 | ||
196 | // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop | ||
197 | // from zero to <= sizeX). The triangle indices are then generated as two triangles | ||
198 | // per heightmap point. There are sizeX by sizeY of these squares. The extra row and | ||
199 | // column of vertices are used to complete the triangles of the last row and column | ||
200 | // of the heightmap. | ||
191 | try | 201 | try |
192 | { | 202 | { |
193 | // One vertice per heightmap value plus the vertices off the top and bottom edge. | 203 | // One vertice per heightmap value plus the vertices off the top and bottom edge. |
@@ -200,16 +210,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
200 | float magY = (float)sizeY / extentY; | 210 | float magY = (float)sizeY / extentY; |
201 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", | 211 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", |
202 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); | 212 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); |
213 | float minHeight = float.MaxValue; | ||
203 | // Note that sizeX+1 vertices are created since there is land between this and the next region. | 214 | // Note that sizeX+1 vertices are created since there is land between this and the next region. |
204 | for (int yy = 0; yy <= sizeY; yy++) | 215 | for (int yy = 0; yy <= sizeY; yy++) |
205 | { | 216 | { |
206 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times | 217 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times |
207 | { | 218 | { |
208 | int offset = yy * sizeX + xx; | 219 | int offset = yy * sizeX + xx; |
209 | // Extend the height from the height from the last row or column | 220 | // Extend the height with the height from the last row or column |
210 | if (yy == sizeY) offset -= sizeX; | 221 | if (yy == sizeY) offset -= sizeX; |
211 | if (xx == sizeX) offset -= 1; | 222 | if (xx == sizeX) offset -= 1; |
212 | float height = heightMap[offset]; | 223 | float height = heightMap[offset]; |
224 | minHeight = Math.Min(minHeight, height); | ||
213 | vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; | 225 | vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; |
214 | vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; | 226 | vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; |
215 | vertices[verticesCount + 2] = height + extentBase.Z; | 227 | vertices[verticesCount + 2] = height + extentBase.Z; |
@@ -217,14 +229,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
217 | } | 229 | } |
218 | } | 230 | } |
219 | verticesCount = verticesCount / 3; | 231 | verticesCount = verticesCount / 3; |
220 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}", | ||
221 | BSScene.DetailLogZero, verticesCount); | ||
222 | 232 | ||
223 | for (int yy = 0; yy < sizeY; yy++) | 233 | for (int yy = 0; yy < sizeY; yy++) |
224 | { | 234 | { |
225 | for (int xx = 0; xx < sizeX; xx++) | 235 | for (int xx = 0; xx < sizeX; xx++) |
226 | { | 236 | { |
227 | int offset = yy * sizeX + xx; | 237 | int offset = yy * (sizeX + 1) + xx; |
228 | // Each vertices is presumed to be the upper left corner of a box of two triangles | 238 | // Each vertices is presumed to be the upper left corner of a box of two triangles |
229 | indices[indicesCount + 0] = offset; | 239 | indices[indicesCount + 0] = offset; |
230 | indices[indicesCount + 1] = offset + 1; | 240 | indices[indicesCount + 1] = offset + 1; |
@@ -235,8 +245,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
235 | indicesCount += 6; | 245 | indicesCount += 6; |
236 | } | 246 | } |
237 | } | 247 | } |
238 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG | 248 | |
239 | LogHeader, indicesCount); // DEBUG | ||
240 | ret = true; | 249 | ret = true; |
241 | } | 250 | } |
242 | catch (Exception e) | 251 | catch (Exception e) |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs deleted file mode 100644 index e60a760..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ /dev/null | |||
@@ -1,1015 +0,0 @@ | |||
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.Runtime.InteropServices; | ||
29 | using System.Security; | ||
30 | using System.Text; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin { | ||
34 | |||
35 | // Classes to allow some type checking for the API | ||
36 | // These hold pointers to allocated objects in the unmanaged space. | ||
37 | |||
38 | // The physics engine controller class created at initialization | ||
39 | public struct BulletSim | ||
40 | { | ||
41 | public BulletSim(uint worldId, BSScene bss, IntPtr xx) | ||
42 | { | ||
43 | ptr = xx; | ||
44 | worldID = worldId; | ||
45 | physicsScene = bss; | ||
46 | } | ||
47 | public IntPtr ptr; | ||
48 | public uint worldID; | ||
49 | // The scene is only in here so very low level routines have a handle to print debug/error messages | ||
50 | public BSScene physicsScene; | ||
51 | } | ||
52 | |||
53 | // An allocated Bullet btRigidBody | ||
54 | public struct BulletBody | ||
55 | { | ||
56 | public BulletBody(uint id, IntPtr xx) | ||
57 | { | ||
58 | ID = id; | ||
59 | ptr = xx; | ||
60 | collisionFilter = 0; | ||
61 | collisionMask = 0; | ||
62 | } | ||
63 | public IntPtr ptr; | ||
64 | public uint ID; | ||
65 | public CollisionFilterGroups collisionFilter; | ||
66 | public CollisionFilterGroups collisionMask; | ||
67 | public override string ToString() | ||
68 | { | ||
69 | StringBuilder buff = new StringBuilder(); | ||
70 | buff.Append("<id="); | ||
71 | buff.Append(ID.ToString()); | ||
72 | buff.Append(",p="); | ||
73 | buff.Append(ptr.ToString("X")); | ||
74 | if (collisionFilter != 0 || collisionMask != 0) | ||
75 | { | ||
76 | buff.Append(",f="); | ||
77 | buff.Append(collisionFilter.ToString("X")); | ||
78 | buff.Append(",m="); | ||
79 | buff.Append(collisionMask.ToString("X")); | ||
80 | } | ||
81 | buff.Append(">"); | ||
82 | return buff.ToString(); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | public struct BulletShape | ||
87 | { | ||
88 | public BulletShape(IntPtr xx) | ||
89 | { | ||
90 | ptr = xx; | ||
91 | type=BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
92 | shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; | ||
93 | isNativeShape = false; | ||
94 | } | ||
95 | public BulletShape(IntPtr xx, BSPhysicsShapeType typ) | ||
96 | { | ||
97 | ptr = xx; | ||
98 | type = typ; | ||
99 | shapeKey = 0; | ||
100 | isNativeShape = false; | ||
101 | } | ||
102 | public IntPtr ptr; | ||
103 | public BSPhysicsShapeType type; | ||
104 | public System.UInt64 shapeKey; | ||
105 | public bool isNativeShape; | ||
106 | public override string ToString() | ||
107 | { | ||
108 | StringBuilder buff = new StringBuilder(); | ||
109 | buff.Append("<p="); | ||
110 | buff.Append(ptr.ToString("X")); | ||
111 | buff.Append(",s="); | ||
112 | buff.Append(type.ToString()); | ||
113 | buff.Append(",k="); | ||
114 | buff.Append(shapeKey.ToString("X")); | ||
115 | buff.Append(",n="); | ||
116 | buff.Append(isNativeShape.ToString()); | ||
117 | buff.Append(">"); | ||
118 | return buff.ToString(); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | // Constraint type values as defined by Bullet | ||
123 | public enum ConstraintType : int | ||
124 | { | ||
125 | POINT2POINT_CONSTRAINT_TYPE = 3, | ||
126 | HINGE_CONSTRAINT_TYPE, | ||
127 | CONETWIST_CONSTRAINT_TYPE, | ||
128 | D6_CONSTRAINT_TYPE, | ||
129 | SLIDER_CONSTRAINT_TYPE, | ||
130 | CONTACT_CONSTRAINT_TYPE, | ||
131 | D6_SPRING_CONSTRAINT_TYPE, | ||
132 | MAX_CONSTRAINT_TYPE | ||
133 | } | ||
134 | |||
135 | // An allocated Bullet btConstraint | ||
136 | public struct BulletConstraint | ||
137 | { | ||
138 | public BulletConstraint(IntPtr xx) | ||
139 | { | ||
140 | ptr = xx; | ||
141 | } | ||
142 | public IntPtr ptr; | ||
143 | } | ||
144 | |||
145 | // An allocated HeightMapThing which holds various heightmap info. | ||
146 | // Made a class rather than a struct so there would be only one | ||
147 | // instance of this and C# will pass around pointers rather | ||
148 | // than making copies. | ||
149 | public class BulletHeightMapInfo | ||
150 | { | ||
151 | public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) { | ||
152 | ID = id; | ||
153 | Ptr = xx; | ||
154 | heightMap = hm; | ||
155 | terrainRegionBase = Vector3.Zero; | ||
156 | minCoords = new Vector3(100f, 100f, 25f); | ||
157 | maxCoords = new Vector3(101f, 101f, 26f); | ||
158 | minZ = maxZ = 0f; | ||
159 | sizeX = sizeY = 256f; | ||
160 | } | ||
161 | public uint ID; | ||
162 | public IntPtr Ptr; | ||
163 | public float[] heightMap; | ||
164 | public Vector3 terrainRegionBase; | ||
165 | public Vector3 minCoords; | ||
166 | public Vector3 maxCoords; | ||
167 | public float sizeX, sizeY; | ||
168 | public float minZ, maxZ; | ||
169 | public BulletShape terrainShape; | ||
170 | public BulletBody terrainBody; | ||
171 | } | ||
172 | |||
173 | // =============================================================================== | ||
174 | [StructLayout(LayoutKind.Sequential)] | ||
175 | public struct ConvexHull | ||
176 | { | ||
177 | Vector3 Offset; | ||
178 | int VertexCount; | ||
179 | Vector3[] Vertices; | ||
180 | } | ||
181 | public enum BSPhysicsShapeType | ||
182 | { | ||
183 | SHAPE_UNKNOWN = 0, | ||
184 | SHAPE_CAPSULE = 1, | ||
185 | SHAPE_BOX = 2, | ||
186 | SHAPE_CONE = 3, | ||
187 | SHAPE_CYLINDER = 4, | ||
188 | SHAPE_SPHERE = 5, | ||
189 | SHAPE_MESH = 6, | ||
190 | SHAPE_HULL = 7, | ||
191 | // following defined by BulletSim | ||
192 | SHAPE_GROUNDPLANE = 20, | ||
193 | SHAPE_TERRAIN = 21, | ||
194 | SHAPE_COMPOUND = 22, | ||
195 | SHAPE_HEIGHTMAP = 23, | ||
196 | }; | ||
197 | |||
198 | // The native shapes have predefined shape hash keys | ||
199 | public enum FixedShapeKey : ulong | ||
200 | { | ||
201 | KEY_NONE = 0, | ||
202 | KEY_BOX = 1, | ||
203 | KEY_SPHERE = 2, | ||
204 | KEY_CONE = 3, | ||
205 | KEY_CYLINDER = 4, | ||
206 | KEY_CAPSULE = 5, | ||
207 | } | ||
208 | |||
209 | [StructLayout(LayoutKind.Sequential)] | ||
210 | public struct ShapeData | ||
211 | { | ||
212 | public uint ID; | ||
213 | public BSPhysicsShapeType Type; | ||
214 | public Vector3 Position; | ||
215 | public Quaternion Rotation; | ||
216 | public Vector3 Velocity; | ||
217 | public Vector3 Scale; | ||
218 | public float Mass; | ||
219 | public float Buoyancy; | ||
220 | public System.UInt64 HullKey; | ||
221 | public System.UInt64 MeshKey; | ||
222 | public float Friction; | ||
223 | public float Restitution; | ||
224 | public float Collidable; // true of things bump into this | ||
225 | public float Static; // true if a static object. Otherwise gravity, etc. | ||
226 | public float Solid; // true if object cannot be passed through | ||
227 | public Vector3 Size; | ||
228 | |||
229 | // note that bools are passed as floats since bool size changes by language and architecture | ||
230 | public const float numericTrue = 1f; | ||
231 | public const float numericFalse = 0f; | ||
232 | } | ||
233 | [StructLayout(LayoutKind.Sequential)] | ||
234 | public struct SweepHit | ||
235 | { | ||
236 | public uint ID; | ||
237 | public float Fraction; | ||
238 | public Vector3 Normal; | ||
239 | public Vector3 Point; | ||
240 | } | ||
241 | [StructLayout(LayoutKind.Sequential)] | ||
242 | public struct RaycastHit | ||
243 | { | ||
244 | public uint ID; | ||
245 | public float Fraction; | ||
246 | public Vector3 Normal; | ||
247 | } | ||
248 | [StructLayout(LayoutKind.Sequential)] | ||
249 | public struct CollisionDesc | ||
250 | { | ||
251 | public uint aID; | ||
252 | public uint bID; | ||
253 | public Vector3 point; | ||
254 | public Vector3 normal; | ||
255 | } | ||
256 | [StructLayout(LayoutKind.Sequential)] | ||
257 | public struct EntityProperties | ||
258 | { | ||
259 | public uint ID; | ||
260 | public Vector3 Position; | ||
261 | public Quaternion Rotation; | ||
262 | public Vector3 Velocity; | ||
263 | public Vector3 Acceleration; | ||
264 | public Vector3 RotationalVelocity; | ||
265 | } | ||
266 | |||
267 | // Format of this structure must match the definition in the C++ code | ||
268 | [StructLayout(LayoutKind.Sequential)] | ||
269 | public struct ConfigurationParameters | ||
270 | { | ||
271 | public float defaultFriction; | ||
272 | public float defaultDensity; | ||
273 | public float defaultRestitution; | ||
274 | public float collisionMargin; | ||
275 | public float gravity; | ||
276 | |||
277 | public float linearDamping; | ||
278 | public float angularDamping; | ||
279 | public float deactivationTime; | ||
280 | public float linearSleepingThreshold; | ||
281 | public float angularSleepingThreshold; | ||
282 | public float ccdMotionThreshold; | ||
283 | public float ccdSweptSphereRadius; | ||
284 | public float contactProcessingThreshold; | ||
285 | |||
286 | public float terrainImplementation; | ||
287 | public float terrainFriction; | ||
288 | public float terrainHitFraction; | ||
289 | public float terrainRestitution; | ||
290 | public float avatarFriction; | ||
291 | public float avatarStandingFriction; | ||
292 | public float avatarDensity; | ||
293 | public float avatarRestitution; | ||
294 | public float avatarCapsuleWidth; | ||
295 | public float avatarCapsuleDepth; | ||
296 | public float avatarCapsuleHeight; | ||
297 | public float avatarContactProcessingThreshold; | ||
298 | |||
299 | public float maxPersistantManifoldPoolSize; | ||
300 | public float maxCollisionAlgorithmPoolSize; | ||
301 | public float shouldDisableContactPoolDynamicAllocation; | ||
302 | public float shouldForceUpdateAllAabbs; | ||
303 | public float shouldRandomizeSolverOrder; | ||
304 | public float shouldSplitSimulationIslands; | ||
305 | public float shouldEnableFrictionCaching; | ||
306 | public float numberOfSolverIterations; | ||
307 | |||
308 | public float linksetImplementation; | ||
309 | public float linkConstraintUseFrameOffset; | ||
310 | public float linkConstraintEnableTransMotor; | ||
311 | public float linkConstraintTransMotorMaxVel; | ||
312 | public float linkConstraintTransMotorMaxForce; | ||
313 | public float linkConstraintERP; | ||
314 | public float linkConstraintCFM; | ||
315 | public float linkConstraintSolverIterations; | ||
316 | |||
317 | public float physicsLoggingFrames; | ||
318 | |||
319 | public const float numericTrue = 1f; | ||
320 | public const float numericFalse = 0f; | ||
321 | } | ||
322 | |||
323 | |||
324 | // The states a bullet collision object can have | ||
325 | public enum ActivationState : uint | ||
326 | { | ||
327 | ACTIVE_TAG = 1, | ||
328 | ISLAND_SLEEPING, | ||
329 | WANTS_DEACTIVATION, | ||
330 | DISABLE_DEACTIVATION, | ||
331 | DISABLE_SIMULATION, | ||
332 | } | ||
333 | |||
334 | public enum CollisionObjectTypes : int | ||
335 | { | ||
336 | CO_COLLISION_OBJECT = 1 << 0, | ||
337 | CO_RIGID_BODY = 1 << 1, | ||
338 | CO_GHOST_OBJECT = 1 << 2, | ||
339 | CO_SOFT_BODY = 1 << 3, | ||
340 | CO_HF_FLUID = 1 << 4, | ||
341 | CO_USER_TYPE = 1 << 5, | ||
342 | } | ||
343 | |||
344 | // Values used by Bullet and BulletSim to control object properties. | ||
345 | // Bullet's "CollisionFlags" has more to do with operations on the | ||
346 | // object (if collisions happen, if gravity effects it, ...). | ||
347 | public enum CollisionFlags : uint | ||
348 | { | ||
349 | CF_STATIC_OBJECT = 1 << 0, | ||
350 | CF_KINEMATIC_OBJECT = 1 << 1, | ||
351 | CF_NO_CONTACT_RESPONSE = 1 << 2, | ||
352 | CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3, | ||
353 | CF_CHARACTER_OBJECT = 1 << 4, | ||
354 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, | ||
355 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, | ||
356 | // Following used by BulletSim to control collisions | ||
357 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, | ||
358 | BS_FLOATS_ON_WATER = 1 << 11, | ||
359 | BS_NONE = 0, | ||
360 | BS_ALL = 0xFFFFFFFF, | ||
361 | |||
362 | // These are the collision flags switched depending on physical state. | ||
363 | // The other flags are used for other things and should not be fooled with. | ||
364 | BS_ACTIVE = CF_STATIC_OBJECT | ||
365 | | CF_KINEMATIC_OBJECT | ||
366 | | CF_NO_CONTACT_RESPONSE | ||
367 | }; | ||
368 | |||
369 | // Values for collisions groups and masks | ||
370 | public enum CollisionFilterGroups : uint | ||
371 | { | ||
372 | // Don't use the bit definitions!! Define the use in a | ||
373 | // filter/mask definition below. This way collision interactions | ||
374 | // are more easily debugged. | ||
375 | BNoneFilter = 0, | ||
376 | BDefaultFilter = 1 << 0, | ||
377 | BStaticFilter = 1 << 1, | ||
378 | BKinematicFilter = 1 << 2, | ||
379 | BDebrisFilter = 1 << 3, | ||
380 | BSensorTrigger = 1 << 4, | ||
381 | BCharacterFilter = 1 << 5, | ||
382 | BAllFilter = 0xFFFFFFFF, | ||
383 | // Filter groups defined by BulletSim | ||
384 | BGroundPlaneFilter = 1 << 10, | ||
385 | BTerrainFilter = 1 << 11, | ||
386 | BRaycastFilter = 1 << 12, | ||
387 | BSolidFilter = 1 << 13, | ||
388 | BLinksetFilter = 1 << 14, | ||
389 | |||
390 | // The collsion filters and masked are defined in one place -- don't want them scattered | ||
391 | AvatarFilter = BCharacterFilter, | ||
392 | AvatarMask = BAllFilter, | ||
393 | ObjectFilter = BSolidFilter, | ||
394 | ObjectMask = BAllFilter, | ||
395 | StaticObjectFilter = BStaticFilter, | ||
396 | StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other | ||
397 | LinksetFilter = BLinksetFilter, | ||
398 | LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other | ||
399 | VolumeDetectFilter = BSensorTrigger, | ||
400 | VolumeDetectMask = ~BSensorTrigger, | ||
401 | TerrainFilter = BTerrainFilter, | ||
402 | TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide | ||
403 | GroundPlaneFilter = BGroundPlaneFilter, | ||
404 | GroundPlaneMask = BAllFilter | ||
405 | |||
406 | }; | ||
407 | |||
408 | // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 | ||
409 | // ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. | ||
410 | public enum ConstraintParams : int | ||
411 | { | ||
412 | BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730 | ||
413 | BT_CONSTRAINT_STOP_ERP, | ||
414 | BT_CONSTRAINT_CFM, | ||
415 | BT_CONSTRAINT_STOP_CFM, | ||
416 | }; | ||
417 | public enum ConstraintParamAxis : int | ||
418 | { | ||
419 | AXIS_LINEAR_X = 0, | ||
420 | AXIS_LINEAR_Y, | ||
421 | AXIS_LINEAR_Z, | ||
422 | AXIS_ANGULAR_X, | ||
423 | AXIS_ANGULAR_Y, | ||
424 | AXIS_ANGULAR_Z, | ||
425 | AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls | ||
426 | AXIS_ANGULAR_ALL, | ||
427 | AXIS_ALL | ||
428 | }; | ||
429 | |||
430 | // =============================================================================== | ||
431 | static class BulletSimAPI { | ||
432 | |||
433 | // Link back to the managed code for outputting log messages | ||
434 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
435 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); | ||
436 | |||
437 | // =============================================================================== | ||
438 | // Initialization and simulation | ||
439 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
440 | public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, | ||
441 | int maxCollisions, IntPtr collisionArray, | ||
442 | int maxUpdates, IntPtr updateArray, | ||
443 | DebugLogCallback logRoutine); | ||
444 | |||
445 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
446 | public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); | ||
447 | |||
448 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
449 | public static extern void SetHeightMap2(IntPtr world, float[] heightmap); | ||
450 | |||
451 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
452 | public static extern void Shutdown2(IntPtr sim); | ||
453 | |||
454 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
455 | public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, | ||
456 | out int updatedEntityCount, | ||
457 | out IntPtr updatedEntitiesPtr, | ||
458 | out int collidersCount, | ||
459 | out IntPtr collidersPtr); | ||
460 | |||
461 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
462 | public static extern bool PushUpdate2(IntPtr obj); | ||
463 | |||
464 | // ===================================================================================== | ||
465 | // Mesh, hull, shape and body creation helper routines | ||
466 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
467 | public static extern IntPtr CreateMeshShape2(IntPtr world, | ||
468 | int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | ||
469 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | ||
470 | |||
471 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
472 | public static extern IntPtr CreateHullShape2(IntPtr world, | ||
473 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); | ||
474 | |||
475 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
476 | public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape); | ||
477 | |||
478 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
479 | public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); | ||
480 | |||
481 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
482 | public static extern bool IsNativeShape2(IntPtr shape); | ||
483 | |||
484 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
485 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); | ||
486 | |||
487 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
488 | public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree); | ||
489 | |||
490 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
491 | public static extern int GetNumberOfCompoundChildren2(IntPtr cShape); | ||
492 | |||
493 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
494 | public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot); | ||
495 | |||
496 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
497 | public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); | ||
498 | |||
499 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
500 | public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); | ||
501 | |||
502 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
503 | public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); | ||
504 | |||
505 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
506 | public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape); | ||
507 | |||
508 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
509 | public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id); | ||
510 | |||
511 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
512 | public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, uint id, IntPtr constructionInfo); | ||
513 | |||
514 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
515 | public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape); | ||
516 | |||
517 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
518 | public static extern int GetBodyType2(IntPtr obj); | ||
519 | |||
520 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
521 | public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
522 | |||
523 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
524 | public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
525 | |||
526 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
527 | public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); | ||
528 | |||
529 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
530 | public static extern IntPtr AllocateBodyInfo2(IntPtr obj); | ||
531 | |||
532 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
533 | public static extern void ReleaseBodyInfo2(IntPtr obj); | ||
534 | |||
535 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
536 | public static extern void DestroyObject2(IntPtr sim, IntPtr obj); | ||
537 | |||
538 | // ===================================================================================== | ||
539 | // Terrain creation and helper routines | ||
540 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
541 | public static extern IntPtr CreateHeightMapInfo2(IntPtr sim, uint id, Vector3 minCoords, Vector3 maxCoords, | ||
542 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin); | ||
543 | |||
544 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
545 | public static extern IntPtr FillHeightMapInfo2(IntPtr sim, IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords, | ||
546 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin); | ||
547 | |||
548 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
549 | public static extern bool ReleaseHeightMapInfo2(IntPtr heightMapInfo); | ||
550 | |||
551 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
552 | public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); | ||
553 | |||
554 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
555 | public static extern IntPtr CreateTerrainShape2(IntPtr mapInfo); | ||
556 | |||
557 | // ===================================================================================== | ||
558 | // Constraint creation and helper routines | ||
559 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
560 | public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
561 | Vector3 frame1loc, Quaternion frame1rot, | ||
562 | Vector3 frame2loc, Quaternion frame2rot, | ||
563 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
564 | |||
565 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
566 | public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
567 | Vector3 joinPoint, | ||
568 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
569 | |||
570 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
571 | public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
572 | Vector3 pivotinA, Vector3 pivotinB, | ||
573 | Vector3 axisInA, Vector3 axisInB, | ||
574 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
575 | |||
576 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
577 | public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); | ||
578 | |||
579 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
580 | public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); | ||
581 | |||
582 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
583 | public static extern bool SetFrames2(IntPtr constrain, | ||
584 | Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); | ||
585 | |||
586 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
587 | public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi); | ||
588 | |||
589 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
590 | public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi); | ||
591 | |||
592 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
593 | public static extern bool UseFrameOffset2(IntPtr constrain, float enable); | ||
594 | |||
595 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
596 | public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce); | ||
597 | |||
598 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
599 | public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); | ||
600 | |||
601 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
602 | public static extern bool CalculateTransforms2(IntPtr constrain); | ||
603 | |||
604 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
605 | public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); | ||
606 | |||
607 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
608 | public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); | ||
609 | |||
610 | // ===================================================================================== | ||
611 | // btCollisionWorld entries | ||
612 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
613 | public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj); | ||
614 | |||
615 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
616 | public static extern void UpdateAabbs2(IntPtr world); | ||
617 | |||
618 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
619 | public static extern bool GetForceUpdateAllAabbs2(IntPtr world); | ||
620 | |||
621 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
622 | public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force); | ||
623 | |||
624 | // ===================================================================================== | ||
625 | // btDynamicsWorld entries | ||
626 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
627 | public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj); | ||
628 | |||
629 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
630 | public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); | ||
631 | |||
632 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
633 | public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); | ||
634 | |||
635 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
636 | public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain); | ||
637 | // ===================================================================================== | ||
638 | // btCollisionObject entries | ||
639 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
640 | public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain); | ||
641 | |||
642 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
643 | public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict); | ||
644 | |||
645 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
646 | public static extern bool HasAnisotripicFriction2(IntPtr constrain); | ||
647 | |||
648 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
649 | public static extern void SetContactProcessingThreshold2(IntPtr obj, float val); | ||
650 | |||
651 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
652 | public static extern float GetContactProcessingThreshold2(IntPtr obj); | ||
653 | |||
654 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
655 | public static extern bool IsStaticObject2(IntPtr obj); | ||
656 | |||
657 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
658 | public static extern bool IsKinematicObject2(IntPtr obj); | ||
659 | |||
660 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
661 | public static extern bool IsStaticOrKinematicObject2(IntPtr obj); | ||
662 | |||
663 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
664 | public static extern bool HasContactResponse2(IntPtr obj); | ||
665 | |||
666 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
667 | public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape); | ||
668 | |||
669 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
670 | public static extern IntPtr GetCollisionShape2(IntPtr obj); | ||
671 | |||
672 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
673 | public static extern int GetActivationState2(IntPtr obj); | ||
674 | |||
675 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
676 | public static extern void SetActivationState2(IntPtr obj, int state); | ||
677 | |||
678 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
679 | public static extern void SetDeactivationTime2(IntPtr obj, float dtime); | ||
680 | |||
681 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
682 | public static extern float GetDeactivationTime2(IntPtr obj); | ||
683 | |||
684 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
685 | public static extern void ForceActivationState2(IntPtr obj, ActivationState state); | ||
686 | |||
687 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
688 | public static extern void Activate2(IntPtr obj, bool forceActivation); | ||
689 | |||
690 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
691 | public static extern bool IsActive2(IntPtr obj); | ||
692 | |||
693 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
694 | public static extern void SetRestitution2(IntPtr obj, float val); | ||
695 | |||
696 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
697 | public static extern float GetRestitution2(IntPtr obj); | ||
698 | |||
699 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
700 | public static extern void SetFriction2(IntPtr obj, float val); | ||
701 | |||
702 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
703 | public static extern float GetFriction2(IntPtr obj); | ||
704 | |||
705 | /* Haven't defined the type 'Transform' | ||
706 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
707 | public static extern Transform GetWorldTransform2(IntPtr obj); | ||
708 | |||
709 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
710 | public static extern void setWorldTransform2(IntPtr obj, Transform trans); | ||
711 | */ | ||
712 | |||
713 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
714 | public static extern Vector3 GetPosition2(IntPtr obj); | ||
715 | |||
716 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
717 | public static extern Quaternion GetOrientation2(IntPtr obj); | ||
718 | |||
719 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
720 | public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); | ||
721 | |||
722 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
723 | public static extern IntPtr GetBroadphaseHandle2(IntPtr obj); | ||
724 | |||
725 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
726 | public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle); | ||
727 | |||
728 | /* | ||
729 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
730 | public static extern Transform GetInterpolationWorldTransform2(IntPtr obj); | ||
731 | |||
732 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
733 | public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans); | ||
734 | */ | ||
735 | |||
736 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
737 | public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel); | ||
738 | |||
739 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
740 | public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel); | ||
741 | |||
742 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
743 | public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel); | ||
744 | |||
745 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
746 | public static extern float GetHitFraction2(IntPtr obj); | ||
747 | |||
748 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
749 | public static extern void SetHitFraction2(IntPtr obj, float val); | ||
750 | |||
751 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
752 | public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); | ||
753 | |||
754 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
755 | public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
756 | |||
757 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
758 | public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
759 | |||
760 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
761 | public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); | ||
762 | |||
763 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
764 | public static extern float GetCcdMotionThreshold2(IntPtr obj); | ||
765 | |||
766 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
767 | public static extern void SetCcdMotionThreshold2(IntPtr obj, float val); | ||
768 | |||
769 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
770 | public static extern float GetCcdSweptSphereRadius2(IntPtr obj); | ||
771 | |||
772 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
773 | public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val); | ||
774 | |||
775 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
776 | public static extern IntPtr GetUserPointer2(IntPtr obj); | ||
777 | |||
778 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
779 | public static extern void SetUserPointer2(IntPtr obj, IntPtr val); | ||
780 | |||
781 | // ===================================================================================== | ||
782 | // btRigidBody entries | ||
783 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
784 | public static extern void ApplyGravity2(IntPtr obj); | ||
785 | |||
786 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
787 | public static extern void SetGravity2(IntPtr obj, Vector3 val); | ||
788 | |||
789 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
790 | public static extern Vector3 GetGravity2(IntPtr obj); | ||
791 | |||
792 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
793 | public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping); | ||
794 | |||
795 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
796 | public static extern void SetLinearDamping2(IntPtr obj, float lin_damping); | ||
797 | |||
798 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
799 | public static extern void SetAngularDamping2(IntPtr obj, float ang_damping); | ||
800 | |||
801 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
802 | public static extern float GetLinearDamping2(IntPtr obj); | ||
803 | |||
804 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
805 | public static extern float GetAngularDamping2(IntPtr obj); | ||
806 | |||
807 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
808 | public static extern float GetLinearSleepingThreshold2(IntPtr obj); | ||
809 | |||
810 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
811 | public static extern float GetAngularSleepingThreshold2(IntPtr obj); | ||
812 | |||
813 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
814 | public static extern void ApplyDamping2(IntPtr obj, float timeStep); | ||
815 | |||
816 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
817 | public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia); | ||
818 | |||
819 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
820 | public static extern Vector3 GetLinearFactor2(IntPtr obj); | ||
821 | |||
822 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
823 | public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor); | ||
824 | |||
825 | /* | ||
826 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
827 | public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans); | ||
828 | */ | ||
829 | |||
830 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
831 | public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot); | ||
832 | |||
833 | // Add a force to the object as if its mass is one. | ||
834 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
835 | public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force); | ||
836 | |||
837 | // Set the force being applied to the object as if its mass is one. | ||
838 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
839 | public static extern void SetObjectForce2(IntPtr obj, Vector3 force); | ||
840 | |||
841 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
842 | public static extern Vector3 GetTotalForce2(IntPtr obj); | ||
843 | |||
844 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
845 | public static extern Vector3 GetTotalTorque2(IntPtr obj); | ||
846 | |||
847 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
848 | public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj); | ||
849 | |||
850 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
851 | public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert); | ||
852 | |||
853 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
854 | public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); | ||
855 | |||
856 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
857 | public static extern void ApplyTorque2(IntPtr obj, Vector3 torque); | ||
858 | |||
859 | // Apply force at the given point. Will add torque to the object. | ||
860 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
861 | public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos); | ||
862 | |||
863 | // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. | ||
864 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
865 | public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp); | ||
866 | |||
867 | // Apply impulse to the object's torque. Force is scaled by object's mass. | ||
868 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
869 | public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp); | ||
870 | |||
871 | // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. | ||
872 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
873 | public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos); | ||
874 | |||
875 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
876 | public static extern void ClearForces2(IntPtr obj); | ||
877 | |||
878 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
879 | public static extern void ClearAllForces2(IntPtr obj); | ||
880 | |||
881 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
882 | public static extern void UpdateInertiaTensor2(IntPtr obj); | ||
883 | |||
884 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
885 | public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj); | ||
886 | |||
887 | /* | ||
888 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
889 | public static extern Transform GetCenterOfMassTransform2(IntPtr obj); | ||
890 | */ | ||
891 | |||
892 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
893 | public static extern Vector3 GetLinearVelocity2(IntPtr obj); | ||
894 | |||
895 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
896 | public static extern Vector3 GetAngularVelocity2(IntPtr obj); | ||
897 | |||
898 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
899 | public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val); | ||
900 | |||
901 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
902 | public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); | ||
903 | |||
904 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
905 | public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos); | ||
906 | |||
907 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
908 | public static extern void Translate2(IntPtr obj, Vector3 trans); | ||
909 | |||
910 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
911 | public static extern void UpdateDeactivation2(IntPtr obj, float timeStep); | ||
912 | |||
913 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
914 | public static extern bool WantsSleeping2(IntPtr obj); | ||
915 | |||
916 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
917 | public static extern void SetAngularFactor2(IntPtr obj, float factor); | ||
918 | |||
919 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
920 | public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor); | ||
921 | |||
922 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
923 | public static extern Vector3 GetAngularFactor2(IntPtr obj); | ||
924 | |||
925 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
926 | public static extern bool IsInWorld2(IntPtr obj); | ||
927 | |||
928 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
929 | public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain); | ||
930 | |||
931 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
932 | public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain); | ||
933 | |||
934 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
935 | public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); | ||
936 | |||
937 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
938 | public static extern int GetNumConstraintRefs2(IntPtr obj); | ||
939 | |||
940 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
941 | public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); | ||
942 | |||
943 | // ===================================================================================== | ||
944 | // btCollisionShape entries | ||
945 | |||
946 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
947 | public static extern float GetAngularMotionDisc2(IntPtr shape); | ||
948 | |||
949 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
950 | public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor); | ||
951 | |||
952 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
953 | public static extern bool IsPolyhedral2(IntPtr shape); | ||
954 | |||
955 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
956 | public static extern bool IsConvex2d2(IntPtr shape); | ||
957 | |||
958 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
959 | public static extern bool IsConvex2(IntPtr shape); | ||
960 | |||
961 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
962 | public static extern bool IsNonMoving2(IntPtr shape); | ||
963 | |||
964 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
965 | public static extern bool IsConcave2(IntPtr shape); | ||
966 | |||
967 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
968 | public static extern bool IsCompound2(IntPtr shape); | ||
969 | |||
970 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
971 | public static extern bool IsSoftBody2(IntPtr shape); | ||
972 | |||
973 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
974 | public static extern bool IsInfinite2(IntPtr shape); | ||
975 | |||
976 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
977 | public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale); | ||
978 | |||
979 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
980 | public static extern Vector3 GetLocalScaling2(IntPtr shape); | ||
981 | |||
982 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
983 | public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass); | ||
984 | |||
985 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
986 | public static extern int GetShapeType2(IntPtr shape); | ||
987 | |||
988 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
989 | public static extern void SetMargin2(IntPtr shape, float val); | ||
990 | |||
991 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
992 | public static extern float GetMargin2(IntPtr shape); | ||
993 | |||
994 | // ===================================================================================== | ||
995 | // Debugging | ||
996 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
997 | public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); | ||
998 | |||
999 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1000 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); | ||
1001 | |||
1002 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1003 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); | ||
1004 | |||
1005 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1006 | public static extern void DumpAllInfo2(IntPtr sim); | ||
1007 | |||
1008 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1009 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | ||
1010 | |||
1011 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1012 | public static extern void DumpPhysicsStatistics2(IntPtr sim); | ||
1013 | |||
1014 | } | ||
1015 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs new file mode 100755 index 0000000..662dd68 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs | |||
@@ -0,0 +1,263 @@ | |||
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 | type = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
108 | shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; | ||
109 | isNativeShape = false; | ||
110 | } | ||
111 | public BSPhysicsShapeType type; | ||
112 | public System.UInt64 shapeKey; | ||
113 | public bool isNativeShape; | ||
114 | |||
115 | public virtual void Clear() { } | ||
116 | public virtual bool HasPhysicalShape { get { return false; } } | ||
117 | // Make another reference to this physical object. | ||
118 | public virtual BulletShape Clone() { return new BulletShape(); } | ||
119 | // Return 'true' if this and other refer to the same physical object | ||
120 | public virtual bool ReferenceSame(BulletShape xx) { return false; } | ||
121 | |||
122 | // Used for log messages for a unique display of the memory/object allocated to this instance | ||
123 | public virtual string AddrString | ||
124 | { | ||
125 | get { return "unknown"; } | ||
126 | } | ||
127 | |||
128 | public override string ToString() | ||
129 | { | ||
130 | StringBuilder buff = new StringBuilder(); | ||
131 | buff.Append("<p="); | ||
132 | buff.Append(AddrString); | ||
133 | buff.Append(",s="); | ||
134 | buff.Append(type.ToString()); | ||
135 | buff.Append(",k="); | ||
136 | buff.Append(shapeKey.ToString("X")); | ||
137 | buff.Append(",n="); | ||
138 | buff.Append(isNativeShape.ToString()); | ||
139 | buff.Append(">"); | ||
140 | return buff.ToString(); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | // An allocated Bullet btConstraint | ||
145 | public class BulletConstraint | ||
146 | { | ||
147 | public BulletConstraint() | ||
148 | { | ||
149 | } | ||
150 | public virtual void Clear() { } | ||
151 | public virtual bool HasPhysicalConstraint { get { return false; } } | ||
152 | |||
153 | // Used for log messages for a unique display of the memory/object allocated to this instance | ||
154 | public virtual string AddrString | ||
155 | { | ||
156 | get { return "unknown"; } | ||
157 | } | ||
158 | } | ||
159 | |||
160 | // An allocated HeightMapThing which holds various heightmap info. | ||
161 | // Made a class rather than a struct so there would be only one | ||
162 | // instance of this and C# will pass around pointers rather | ||
163 | // than making copies. | ||
164 | public class BulletHMapInfo | ||
165 | { | ||
166 | public BulletHMapInfo(uint id, float[] hm) { | ||
167 | ID = id; | ||
168 | heightMap = hm; | ||
169 | terrainRegionBase = OMV.Vector3.Zero; | ||
170 | minCoords = new OMV.Vector3(100f, 100f, 25f); | ||
171 | maxCoords = new OMV.Vector3(101f, 101f, 26f); | ||
172 | minZ = maxZ = 0f; | ||
173 | sizeX = sizeY = 256f; | ||
174 | } | ||
175 | public uint ID; | ||
176 | public float[] heightMap; | ||
177 | public OMV.Vector3 terrainRegionBase; | ||
178 | public OMV.Vector3 minCoords; | ||
179 | public OMV.Vector3 maxCoords; | ||
180 | public float sizeX, sizeY; | ||
181 | public float minZ, maxZ; | ||
182 | public BulletShape terrainShape; | ||
183 | public BulletBody terrainBody; | ||
184 | } | ||
185 | |||
186 | // The general class of collsion object. | ||
187 | public enum CollisionType | ||
188 | { | ||
189 | Avatar, | ||
190 | Groundplane, | ||
191 | Terrain, | ||
192 | Static, | ||
193 | Dynamic, | ||
194 | VolumeDetect, | ||
195 | // Linkset, // A linkset should be either Static or Dynamic | ||
196 | LinksetChild, | ||
197 | Unknown | ||
198 | }; | ||
199 | |||
200 | // Hold specification of group and mask collision flags for a CollisionType | ||
201 | public struct CollisionTypeFilterGroup | ||
202 | { | ||
203 | public CollisionTypeFilterGroup(CollisionType t, uint g, uint m) | ||
204 | { | ||
205 | type = t; | ||
206 | group = g; | ||
207 | mask = m; | ||
208 | } | ||
209 | public CollisionType type; | ||
210 | public uint group; | ||
211 | public uint mask; | ||
212 | }; | ||
213 | |||
214 | public static class BulletSimData | ||
215 | { | ||
216 | |||
217 | // Map of collisionTypes to flags for collision groups and masks. | ||
218 | // As mentioned above, don't use the CollisionFilterGroups definitions directly in the code | ||
219 | // but, instead, use references to this dictionary. Finding and debugging | ||
220 | // collision flag problems will be made easier. | ||
221 | public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks | ||
222 | = new Dictionary<CollisionType, CollisionTypeFilterGroup>() | ||
223 | { | ||
224 | { CollisionType.Avatar, | ||
225 | new CollisionTypeFilterGroup(CollisionType.Avatar, | ||
226 | (uint)CollisionFilterGroups.BCharacterGroup, | ||
227 | (uint)CollisionFilterGroups.BAllGroup) | ||
228 | }, | ||
229 | { CollisionType.Groundplane, | ||
230 | new CollisionTypeFilterGroup(CollisionType.Groundplane, | ||
231 | (uint)CollisionFilterGroups.BGroundPlaneGroup, | ||
232 | (uint)CollisionFilterGroups.BAllGroup) | ||
233 | }, | ||
234 | { CollisionType.Terrain, | ||
235 | new CollisionTypeFilterGroup(CollisionType.Terrain, | ||
236 | (uint)CollisionFilterGroups.BTerrainGroup, | ||
237 | (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) | ||
238 | }, | ||
239 | { CollisionType.Static, | ||
240 | new CollisionTypeFilterGroup(CollisionType.Static, | ||
241 | (uint)CollisionFilterGroups.BStaticGroup, | ||
242 | (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | ||
243 | }, | ||
244 | { CollisionType.Dynamic, | ||
245 | new CollisionTypeFilterGroup(CollisionType.Dynamic, | ||
246 | (uint)CollisionFilterGroups.BSolidGroup, | ||
247 | (uint)(CollisionFilterGroups.BAllGroup)) | ||
248 | }, | ||
249 | { CollisionType.VolumeDetect, | ||
250 | new CollisionTypeFilterGroup(CollisionType.VolumeDetect, | ||
251 | (uint)CollisionFilterGroups.BSensorTrigger, | ||
252 | (uint)(~CollisionFilterGroups.BSensorTrigger)) | ||
253 | }, | ||
254 | { CollisionType.LinksetChild, | ||
255 | new CollisionTypeFilterGroup(CollisionType.LinksetChild, | ||
256 | (uint)CollisionFilterGroups.BLinksetChildGroup, | ||
257 | (uint)(CollisionFilterGroups.BNoneGroup)) | ||
258 | // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | ||
259 | }, | ||
260 | }; | ||
261 | |||
262 | } | ||
263 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt new file mode 100755 index 0000000..facf720 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | |||
@@ -0,0 +1,276 @@ | |||
1 | CURRENT PRIORITIES | ||
2 | ================================================= | ||
3 | Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE) | ||
4 | Meshes rendering as bounding boxes | ||
5 | llMoveToTarget | ||
6 | Vehicle movement on terrain smoothness | ||
7 | limitMotorUp calibration (more down?) | ||
8 | Preferred orientatino angular correction fix | ||
9 | Surfboard go wonky when turning | ||
10 | Angular motor direction is global coordinates rather than local coordinates? | ||
11 | Boats float low in the water | ||
12 | Avatar movement | ||
13 | flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) | ||
14 | walking up stairs is not calibrated correctly (stairs out of Kepler cabin) | ||
15 | avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) | ||
16 | Enable vehicle border crossings (at least as poorly as ODE) | ||
17 | Terrain skirts | ||
18 | Avatar created in previous region and not new region when crossing border | ||
19 | Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) | ||
20 | Vehicle script tuning/debugging | ||
21 | Avanti speed script | ||
22 | Weapon shooter script | ||
23 | Add material densities to the material types | ||
24 | |||
25 | CRASHES | ||
26 | ================================================= | ||
27 | 20121129.1411: editting/moving phys object across region boundries causes crash | ||
28 | getPos-> btRigidBody::upcast -> getBodyType -> BOOM | ||
29 | 20121128.1600: mesh object not rezzing (no physics mesh). | ||
30 | Causes many errors. Doesn't stop after first error with box shape. | ||
31 | Eventually crashes when deleting the object. | ||
32 | 20121206.1434: rez Sam-pan into OSGrid BulletSim11 region | ||
33 | Immediate simulator crash. Mono does not output any stacktrace and | ||
34 | log just stops after reporting taint-time linking of the linkset. | ||
35 | |||
36 | VEHICLES TODO LIST: | ||
37 | ================================================= | ||
38 | Angular motor direction is global coordinates rather than local coordinates | ||
39 | Border crossing with linked vehicle causes crash | ||
40 | Vehicles (Move smoothly) | ||
41 | Add vehicle collisions so IsColliding is properly reported. | ||
42 | Needed for banking, limitMotorUp, movementLimiting, ... | ||
43 | VehicleAddForce is not scaled by the simulation step but it is only | ||
44 | applied for one step. Should it be scaled? | ||
45 | Some vehicles should not be able to turn if no speed or off ground. | ||
46 | Cannot edit/move a vehicle being ridden: it jumps back to the origional position. | ||
47 | Neb car jiggling left and right | ||
48 | Happens on terrain and any other mesh object. Flat cubes are much smoother. | ||
49 | This has been reduced but not eliminated. | ||
50 | Implement referenceFrame for all the motion routines. | ||
51 | Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. | ||
52 | Verify that angular motion specified around Z moves in the vehicle coordinates. | ||
53 | Verify llGetVel() is returning a smooth and good value for vehicle movement. | ||
54 | llGetVel() should return the root's velocity if requested in a child prim. | ||
55 | Implement function efficiency for lineaar and angular motion. | ||
56 | After getting off a vehicle, the root prim is phantom (can be walked through) | ||
57 | Need to force a position update for the root prim after compound shape destruction | ||
58 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) | ||
59 | For limitMotorUp, use raycast down to find if vehicle is in the air. | ||
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 | |||
66 | BULLETSIM TODO LIST: | ||
67 | ================================================= | ||
68 | Implement an avatar mesh shape. The Bullet capsule is way too limited. | ||
69 | Consider just hand creating a vertex/index array in a new BSShapeAvatar. | ||
70 | Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. | ||
71 | Duplicating a physical prim causes old prim to jump away | ||
72 | Dup a phys prim and the original become unselected and thus interacts w/ selected prim. | ||
73 | Scenes with hundred of thousands of static objects take a lot of physics CPU time. | ||
74 | BSPrim.Force should set a continious force on the prim. The force should be | ||
75 | applied each tick. Some limits? | ||
76 | Gun sending shooter flying. | ||
77 | Collision margin (gap between physical objects lying on each other) | ||
78 | Boundry checking (crashes related to crossing boundry) | ||
79 | Add check for border edge position for avatars and objects. | ||
80 | Verify the events are created for border crossings. | ||
81 | Avatar rotation (check out changes to ScenePresence for physical rotation) | ||
82 | Avatar running (what does phys engine need to do?) | ||
83 | Small physical objects do not interact correctly | ||
84 | Create chain of .5x.5x.1 torui and make all but top physical so to hang. | ||
85 | The chain will fall apart and pairs will dance around on ground | ||
86 | Chains of 1x1x.2 will stay connected but will dance. | ||
87 | Chains above 2x2x.4 are more stable and get stablier as torui get larger. | ||
88 | Add PID motor for avatar movement (slow to stop, ...) | ||
89 | setForce should set a constant force. Different than AddImpulse. | ||
90 | Implement raycast. | ||
91 | Implement ShapeCollection.Dispose() | ||
92 | Implement water as a plain so raycasting and collisions can happen with same. | ||
93 | Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE | ||
94 | Also osGetPhysicsEngineVerion() maybe. | ||
95 | Linkset.Position and Linkset.Orientation requre rewrite to properly return | ||
96 | child position. LinksetConstraint acts like it's at taint time!! | ||
97 | Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F) | ||
98 | Should the different PID factors have non-equal contributions for different | ||
99 | values of Efficiency? | ||
100 | Selecting and deselecting physical objects causes CPU processing time to jump | ||
101 | http://www.youtube.com/watch?v=Hjg57fWg8yI&hd=1 | ||
102 | put thousand physical objects, select and deselect same. CPU time will be large. | ||
103 | Re-implement buoyancy as a separate force on the object rather than diddling gravity. | ||
104 | Register a pre-step event to add the force. | ||
105 | More efficient memory usage when passing hull information from BSPrim to BulletSim | ||
106 | Avatar movement motor check for zero or small movement. Somehow suppress small movements | ||
107 | when avatar has stopped and is just standing. Simple test for near zero has | ||
108 | the problem of preventing starting up (increase from zero) especially when falling. | ||
109 | Physical and phantom will drop through the terrain | ||
110 | |||
111 | |||
112 | LINKSETS | ||
113 | ====================================================== | ||
114 | Offset the center of the linkset to be the geometric center of all the prims | ||
115 | Not quite the same as the center-of-gravity | ||
116 | Linksets should allow collisions to individual children | ||
117 | Add LocalID to children shapes in LinksetCompound and create events for individuals | ||
118 | LinksetCompound: when one of the children changes orientation (like tires | ||
119 | turning on a vehicle, the whole compound object is rebuilt. Optimize this | ||
120 | so orientation/position of individual children can change without a rebuild. | ||
121 | Verify/think through scripts in children of linksets. What do they reference | ||
122 | and return when getting position, velocity, ... | ||
123 | Confirm constraint linksets still work after making all the changes for compound linksets. | ||
124 | Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt. | ||
125 | For compound linksets, add ability to remove or reposition individual child shapes. | ||
126 | Disable activity of passive linkset children. | ||
127 | Since the linkset is a compound object, the old prims are left lying | ||
128 | around and need to be phantomized so they don't collide, ... | ||
129 | Speed up creation of large physical linksets | ||
130 | For instance, sitting in Neb's car (130 prims) takes several seconds to become physical. | ||
131 | REALLY bad for very large physical linksets (freezes the sim for many seconds). | ||
132 | Eliminate collisions between objects in a linkset. (LinksetConstraint) | ||
133 | Have UserPointer point to struct with localID and linksetID? | ||
134 | Objects in original linkset still collide with each other? | ||
135 | |||
136 | MORE | ||
137 | ====================================================== | ||
138 | Test avatar walking up stairs. How does compare with SL. | ||
139 | Radius of the capsule affects ability to climb edges. | ||
140 | Debounce avatar contact so legs don't keep folding up when standing. | ||
141 | Implement LSL physics controls. Like STATUS_ROTATE_X. | ||
142 | Add border extensions to terrain to help region crossings and objects leaving region. | ||
143 | Use a different capsule shape for avatar when sitting | ||
144 | LL uses a pyrimidal shape scaled by the avatar's bounding box | ||
145 | http://wiki.secondlife.com/wiki/File:Avmeshforms.png | ||
146 | |||
147 | Performance test with lots of avatars. Can BulletSim support a thousand? | ||
148 | Optimize collisions in C++: only send up to the object subscribed to collisions. | ||
149 | Use collision subscription and remove the collsion(A,B) and collision(B,A) | ||
150 | Check whether SimMotionState needs large if statement (see TODO). | ||
151 | |||
152 | Implement 'top colliders' info. | ||
153 | Avatar jump | ||
154 | Performance measurement and changes to make quicker. | ||
155 | Implement detailed physics stats (GetStats()). | ||
156 | |||
157 | Measure performance improvement from hulls | ||
158 | Test not using ghost objects for volume detect implementation. | ||
159 | Performance of closures and delegates for taint processing | ||
160 | Are there faster ways? | ||
161 | Is any slowdown introduced by the existing implementation significant? | ||
162 | Is there are more efficient method of implementing pre and post step actions? | ||
163 | See http://www.codeproject.com/Articles/29922/Weak-Events-in-C | ||
164 | |||
165 | Physics Arena central pyramid: why is one side permiable? | ||
166 | |||
167 | In SL, perfect spheres don't seem to have rolling friction. Add special case. | ||
168 | Enforce physical parameter min/max: | ||
169 | Gravity: [-1, 28] | ||
170 | Friction: [0, 255] | ||
171 | Density: [1, 22587] | ||
172 | Restitution [0, 1] | ||
173 | http://wiki.secondlife.com/wiki/Physics_Material_Settings_test | ||
174 | Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html | ||
175 | |||
176 | INTERNAL IMPROVEMENT/CLEANUP | ||
177 | ================================================= | ||
178 | Create the physical wrapper classes (BulletBody, BulletShape) by methods on | ||
179 | BSAPITemplate and make their actual implementation Bullet engine specific. | ||
180 | For the short term, just call the existing functions in ShapeCollection. | ||
181 | Consider moving prim/character body and shape destruction in destroy() | ||
182 | to postTimeTime rather than protecting all the potential sets that | ||
183 | might have been queued up. | ||
184 | Remove unused fields from ShapeData (not used in API2) | ||
185 | Remove unused fields from pinned memory shared parameter block | ||
186 | Create parameter variables in BSScene to replace same. | ||
187 | Breakout code for mesh/hull/compound/native into separate BSShape* classes | ||
188 | Standardize access to building and reference code. | ||
189 | The skeleton classes are in the sources but are not complete or linked in. | ||
190 | Make BSBody and BSShape real classes to centralize creation/changin/destruction | ||
191 | Convert state and parameter calls from BulletSimAPI direct calls to | ||
192 | calls on BSBody and BSShape | ||
193 | Generalize Dynamics and PID with standardized motors. | ||
194 | Generalize Linkset and vehicles into PropertyManagers | ||
195 | Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies | ||
196 | Potentially add events for shape destruction, etc. | ||
197 | Complete implemention of preStepActions | ||
198 | Replace vehicle step call with prestep event. | ||
199 | Is there a need for postStepActions? postStepTaints? | ||
200 | Implement linkset by setting position of children when root updated. (LinksetManual) | ||
201 | Linkset implementation using manual prim movement. | ||
202 | LinkablePrim class? Would that simplify/centralize the linkset logic? | ||
203 | BSScene.UpdateParameterSet() is broken. How to set params on objects? | ||
204 | Remove HeightmapInfo from terrain specification | ||
205 | Since C++ code does not need terrain height, this structure et al are not needed. | ||
206 | Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will | ||
207 | bob at the water level. BSPrim.PositionSanityCheck(). | ||
208 | Should taints check for existance or activeness of target? | ||
209 | When destroying linksets/etc, taints can be generated for objects that are | ||
210 | actually gone when the taint happens. Crashes don't happen because the taint closure | ||
211 | keeps the object from being freed, but that is just an accident. | ||
212 | Possibly have and 'active' flag that is checked by the taint processor? | ||
213 | Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones) | ||
214 | Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'? | ||
215 | There are TOO MANY interfaces from BulletSim core to Bullet itself | ||
216 | Think of something to eliminate one or more of the layers | ||
217 | |||
218 | THREADING | ||
219 | ================================================= | ||
220 | Do taint action immediately if not actually executing Bullet. | ||
221 | Add lock around Bullet execution and just do taint actions if simulation is not happening. | ||
222 | |||
223 | DONE DONE DONE DONE | ||
224 | ================================================= | ||
225 | Cleanup code in BSDynamics by using motors. (Resolution: started) | ||
226 | Consider implementing terrain with a mesh rather than heightmap. (Resolution: done) | ||
227 | Would have better and adjustable resolution. | ||
228 | Build terrain mesh so heighmap is height of the center of the square meter. | ||
229 | Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional. | ||
230 | Terrain as mesh. (Resolution: done) | ||
231 | How are static linksets seen by the physics engine? | ||
232 | Resolution: they are not linked in physics. When moved, all the children are repositioned. | ||
233 | Convert BSCharacter to use all API2 (Resolution: done) | ||
234 | Avatar pushing difficult (too heavy?) | ||
235 | Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done) | ||
236 | Remove old code in DLL (all non-API2 stuff). (Resolution: done) | ||
237 | Measurements of mega-physical prim performance (with graph) (Resolution: done, email) | ||
238 | Debug Bullet internal stats output (why is timing all wrong?) | ||
239 | Resolution: Bullet stats logging only works with a single instance of Bullet (one region). | ||
240 | Implement meshes or just verify that they work. (Resolution: they do!) | ||
241 | Do prim hash codes work for sculpties and meshes? (Resolution: yes) | ||
242 | Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound) | ||
243 | Compound shapes will need the LocalID in the shapes and collision | ||
244 | processing to get it from there. | ||
245 | Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.) | ||
246 | Package Bullet source mods for Bullet internal stats output | ||
247 | (Resolution: move code into WorldData.h rather than relying on patches) | ||
248 | Single prim vehicles don't seem to properly vehiclize. | ||
249 | (Resolution: mass was not getting set properly for single prim linksets) | ||
250 | Add material type linkage and input all the material property definitions. | ||
251 | Skeleton classes and table are in the sources but are not filled or used. | ||
252 | (Resolution: | ||
253 | Neb vehicle taking > 25ms of physics time!! | ||
254 | (Resolution: compound linksets were being rebuild WAY too often) | ||
255 | Avatar height off after unsitting (floats off ground) | ||
256 | Editting appearance then moving restores. | ||
257 | Must not be initializing height when recreating capsule after unsit. | ||
258 | (Resolution: confusion of scale vs size for native objects removed) | ||
259 | Light cycle falling over when driving (Resolution: implemented angularMotorUp) | ||
260 | Should vehicle angular/linear movement friction happen after all the components | ||
261 | or does it only apply to the basic movement? | ||
262 | (Resolution: friction added before returning newly computed motor value. | ||
263 | What is expected by some vehicles (turning up friction to moderate speed)) | ||
264 | Tune terrain/object friction to be closer to SL. | ||
265 | (Resolution: added material type with friction and resolution) | ||
266 | Smooth avatar movement with motor (DONE) | ||
267 | Should motor update be all at taint-time? (Yes, DONE) | ||
268 | Fix avatar slowly sliding when standing (zero motion when stopped) (DONE) | ||
269 | (Resolution: added BSVMotor for avatar starting and stopping) | ||
270 | llApplyImpulse() | ||
271 | Compare mass/movement in OS and SL. Calibrate actions. (DONE) | ||
272 | (Resolution: tested on SL and OS. AddForce scales the force for timestep) | ||
273 | llSetBuoyancy() (DONE) | ||
274 | (Resolution: Bullet resets object gravity when added to world. Moved set gravity) | ||
275 | Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE) | ||
276 | (Resolution: set default density to 3.5 (from 60) which is closer to SL) | ||
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs index 8de70ef..ba24aa7 100644 --- a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs | |||
@@ -2190,7 +2190,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2190 | convex = false; | 2190 | convex = false; |
2191 | try | 2191 | try |
2192 | { | 2192 | { |
2193 | _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, (int)LevelOfDetail.High, true,convex,false); | 2193 | _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, (int)LevelOfDetail.High, true,false,convex,false); |
2194 | } | 2194 | } |
2195 | catch | 2195 | catch |
2196 | { | 2196 | { |
@@ -2557,7 +2557,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2557 | 2557 | ||
2558 | try | 2558 | try |
2559 | { | 2559 | { |
2560 | mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, (int)LevelOfDetail.High, true, convex,false); | 2560 | mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, (int)LevelOfDetail.High, true, false,convex,false); |
2561 | } | 2561 | } |
2562 | catch | 2562 | catch |
2563 | { | 2563 | { |
diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs index ecc2918..df980ab 100644 --- a/OpenSim/Region/Physics/Manager/IMesher.cs +++ b/OpenSim/Region/Physics/Manager/IMesher.cs | |||
@@ -37,7 +37,7 @@ namespace OpenSim.Region.Physics.Manager | |||
37 | { | 37 | { |
38 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); | 38 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); |
39 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); | 39 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); |
40 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde); | 40 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde); |
41 | IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex); | 41 | IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex); |
42 | void ReleaseMesh(IMesh mesh); | 42 | void ReleaseMesh(IMesh mesh); |
43 | void ExpireReleaseMeshs(); | 43 | void ExpireReleaseMeshs(); |
diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index 9338130..e2789d6 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs | |||
@@ -349,17 +349,20 @@ namespace OpenSim.Region.Physics.Manager | |||
349 | } | 349 | } |
350 | 350 | ||
351 | /// <summary> | 351 | /// <summary> |
352 | /// Velocity of this actor. | 352 | /// The desired velocity of this actor. |
353 | /// </summary> | 353 | /// </summary> |
354 | /// <remarks> | 354 | /// <remarks> |
355 | /// Setting this provides a target velocity for physics scene updates. | 355 | /// Setting this provides a target velocity for physics scene updates. |
356 | /// Getting this returns the velocity calculated by physics scene updates, using factors such as target velocity, | 356 | /// Getting this returns the last set target. Fetch Velocity to get the current velocity. |
357 | /// time to accelerate and collisions. | ||
358 | /// </remarks> | 357 | /// </remarks> |
358 | protected Vector3 m_targetVelocity; | ||
359 | public virtual Vector3 TargetVelocity | 359 | public virtual Vector3 TargetVelocity |
360 | { | 360 | { |
361 | get { return Velocity; } | 361 | get { return m_targetVelocity; } |
362 | set { Velocity = value; } | 362 | set { |
363 | m_targetVelocity = value; | ||
364 | Velocity = m_targetVelocity; | ||
365 | } | ||
363 | } | 366 | } |
364 | 367 | ||
365 | public abstract Vector3 Velocity { get; set; } | 368 | public abstract Vector3 Velocity { get; set; } |
diff --git a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs b/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs index 8587a2b..8ccfda5 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs | |||
@@ -30,7 +30,7 @@ using System.Collections.Generic; | |||
30 | using System.IO; | 30 | using System.IO; |
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using Nini.Config; | 32 | using Nini.Config; |
33 | using log4net; | 33 | using log4net; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | 35 | ||
36 | namespace OpenSim.Region.Physics.Manager | 36 | namespace OpenSim.Region.Physics.Manager |
diff --git a/OpenSim/Region/Physics/Manager/ZeroMesher.cs b/OpenSim/Region/Physics/Manager/ZeroMesher.cs index 16846e6..80ecf66 100644 --- a/OpenSim/Region/Physics/Manager/ZeroMesher.cs +++ b/OpenSim/Region/Physics/Manager/ZeroMesher.cs | |||
@@ -64,16 +64,21 @@ namespace OpenSim.Region.Physics.Manager | |||
64 | { | 64 | { |
65 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 65 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
66 | { | 66 | { |
67 | return CreateMesh(primName, primShape, size, lod, false); | 67 | return CreateMesh(primName, primShape, size, lod, false, false); |
68 | } | 68 | } |
69 | 69 | ||
70 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex,bool forOde) | 70 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex,bool forOde) |
71 | { | 71 | { |
72 | return CreateMesh(primName, primShape, size, lod, false); | 72 | return CreateMesh(primName, primShape, size, lod, false); |
73 | } | 73 | } |
74 | 74 | ||
75 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) | 75 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) |
76 | { | 76 | { |
77 | return CreateMesh(primName, primShape, size, lod, false, false); | ||
78 | } | ||
79 | |||
80 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache) | ||
81 | { | ||
77 | // Remove the reference to the encoded JPEG2000 data so it can be GCed | 82 | // Remove the reference to the encoded JPEG2000 data so it can be GCed |
78 | primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; | 83 | primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; |
79 | 84 | ||
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index f629c4d..d181b78 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs | |||
@@ -321,6 +321,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
321 | 321 | ||
322 | if (primShape.SculptData.Length <= 0) | 322 | if (primShape.SculptData.Length <= 0) |
323 | { | 323 | { |
324 | // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this | ||
325 | // method twice - once before it has loaded sculpt data from the asset service and once afterwards. | ||
326 | // The first time will always call with unloaded SculptData if this needs to be uploaded. | ||
324 | // m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); | 327 | // m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); |
325 | return false; | 328 | return false; |
326 | } | 329 | } |
@@ -699,16 +702,21 @@ namespace OpenSim.Region.Physics.Meshing | |||
699 | 702 | ||
700 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 703 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
701 | { | 704 | { |
702 | return CreateMesh(primName, primShape, size, lod, false); | 705 | return CreateMesh(primName, primShape, size, lod, false, true); |
703 | } | 706 | } |
704 | 707 | ||
705 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde) | 708 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde) |
706 | { | 709 | { |
707 | return CreateMesh(primName, primShape, size, lod, false); | 710 | return CreateMesh(primName, primShape, size, lod, false); |
708 | } | 711 | } |
709 | 712 | ||
710 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) | 713 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) |
711 | { | 714 | { |
715 | return CreateMesh(primName, primShape, size, lod, isPhysical, true); | ||
716 | } | ||
717 | |||
718 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache) | ||
719 | { | ||
712 | #if SPAM | 720 | #if SPAM |
713 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); | 721 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); |
714 | #endif | 722 | #endif |
@@ -718,9 +726,12 @@ namespace OpenSim.Region.Physics.Meshing | |||
718 | 726 | ||
719 | // If this mesh has been created already, return it instead of creating another copy | 727 | // If this mesh has been created already, return it instead of creating another copy |
720 | // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory | 728 | // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory |
721 | key = primShape.GetMeshKey(size, lod); | 729 | if (shouldCache) |
722 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | 730 | { |
723 | return mesh; | 731 | key = primShape.GetMeshKey(size, lod); |
732 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | ||
733 | return mesh; | ||
734 | } | ||
724 | 735 | ||
725 | if (size.X < 0.01f) size.X = 0.01f; | 736 | if (size.X < 0.01f) size.X = 0.01f; |
726 | if (size.Y < 0.01f) size.Y = 0.01f; | 737 | if (size.Y < 0.01f) size.Y = 0.01f; |
@@ -743,7 +754,10 @@ namespace OpenSim.Region.Physics.Meshing | |||
743 | // trim the vertex and triangle lists to free up memory | 754 | // trim the vertex and triangle lists to free up memory |
744 | mesh.TrimExcess(); | 755 | mesh.TrimExcess(); |
745 | 756 | ||
746 | m_uniqueMeshes.Add(key, mesh); | 757 | if (shouldCache) |
758 | { | ||
759 | m_uniqueMeshes.Add(key, mesh); | ||
760 | } | ||
747 | } | 761 | } |
748 | 762 | ||
749 | return mesh; | 763 | return mesh; |
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index a59f63f..d09aa62 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | |||
@@ -3367,6 +3367,11 @@ Console.WriteLine(" JointCreateFixed"); | |||
3367 | _pbs.SculptData = new byte[asset.Data.Length]; | 3367 | _pbs.SculptData = new byte[asset.Data.Length]; |
3368 | asset.Data.CopyTo(_pbs.SculptData, 0); | 3368 | asset.Data.CopyTo(_pbs.SculptData, 0); |
3369 | // m_assetFailed = false; | 3369 | // m_assetFailed = false; |
3370 | |||
3371 | // m_log.DebugFormat( | ||
3372 | // "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}", | ||
3373 | // _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name); | ||
3374 | |||
3370 | m_taintshape = true; | 3375 | m_taintshape = true; |
3371 | _parent_scene.AddPhysicsActorTaint(this); | 3376 | _parent_scene.AddPhysicsActorTaint(this); |
3372 | } | 3377 | } |
diff --git a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs index cbc6b95..16404c6 100644 --- a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs +++ b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs | |||
@@ -32,13 +32,14 @@ using OpenMetaverse; | |||
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenSim.Region.Physics.Manager; | 33 | using OpenSim.Region.Physics.Manager; |
34 | using OpenSim.Region.Physics.OdePlugin; | 34 | using OpenSim.Region.Physics.OdePlugin; |
35 | using OpenSim.Tests.Common; | ||
35 | using log4net; | 36 | using log4net; |
36 | using System.Reflection; | 37 | using System.Reflection; |
37 | 38 | ||
38 | namespace OpenSim.Region.Physics.OdePlugin.Tests | 39 | namespace OpenSim.Region.Physics.OdePlugin.Tests |
39 | { | 40 | { |
40 | [TestFixture] | 41 | [TestFixture] |
41 | public class ODETestClass | 42 | public class ODETestClass : OpenSimTestCase |
42 | { | 43 | { |
43 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
44 | 45 | ||
diff --git a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs index 6e1a105..00cbfbd 100644 --- a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs | |||
@@ -1031,12 +1031,12 @@ namespace OpenSim.Region.Physics.Meshing | |||
1031 | 1031 | ||
1032 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 1032 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
1033 | { | 1033 | { |
1034 | return CreateMesh(primName, primShape, size, lod, false,false,false); | 1034 | return CreateMesh(primName, primShape, size, lod, false,false,false,false); |
1035 | } | 1035 | } |
1036 | 1036 | ||
1037 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) | 1037 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) |
1038 | { | 1038 | { |
1039 | return CreateMesh(primName, primShape, size, lod, false,false,false); | 1039 | return CreateMesh(primName, primShape, size, lod, false,false,false,false); |
1040 | } | 1040 | } |
1041 | 1041 | ||
1042 | public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex) | 1042 | public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex) |
@@ -1080,7 +1080,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
1080 | 1080 | ||
1081 | private static Vector3 m_MeshUnitSize = new Vector3(1.0f, 1.0f, 1.0f); | 1081 | private static Vector3 m_MeshUnitSize = new Vector3(1.0f, 1.0f, 1.0f); |
1082 | 1082 | ||
1083 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde) | 1083 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde) |
1084 | { | 1084 | { |
1085 | #if SPAM | 1085 | #if SPAM |
1086 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); | 1086 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); |
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs index 5030cec..0df71eb 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs | |||
@@ -448,7 +448,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
448 | else | 448 | else |
449 | { | 449 | { |
450 | repData.meshState = MeshState.needMesh; | 450 | repData.meshState = MeshState.needMesh; |
451 | mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true); | 451 | mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, false, convex, true); |
452 | if (mesh == null) | 452 | if (mesh == null) |
453 | { | 453 | { |
454 | repData.meshState = MeshState.MeshFailed; | 454 | repData.meshState = MeshState.MeshFailed; |
@@ -513,7 +513,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
513 | clod = (int)LevelOfDetail.Low; | 513 | clod = (int)LevelOfDetail.Low; |
514 | } | 514 | } |
515 | 515 | ||
516 | mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true); | 516 | mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, false, convex, true); |
517 | 517 | ||
518 | if (mesh == null) | 518 | if (mesh == null) |
519 | { | 519 | { |
@@ -929,4 +929,4 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
929 | repData.actor.Name); | 929 | repData.actor.Name); |
930 | } | 930 | } |
931 | } | 931 | } |
932 | } \ No newline at end of file | 932 | } |