opensim – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | eva | 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.BulletSPlugin |
||
39 | { |
||
40 | |||
41 | [Serializable] |
||
42 | public class BSPrim : BSPhysObject |
||
43 | { |
||
44 | protected 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 | |||
54 | private float _mass; // the mass of this object |
||
55 | private OMV.Vector3 _acceleration; |
||
56 | private int _physicsActorType; |
||
57 | private bool _isPhysical; |
||
58 | private bool _flying; |
||
59 | private bool _setAlwaysRun; |
||
60 | private bool _throttleUpdates; |
||
61 | private bool _floatOnWater; |
||
62 | private OMV.Vector3 _rotationalVelocity; |
||
63 | private bool _kinematic; |
||
64 | private float _buoyancy; |
||
65 | |||
66 | private int CrossingFailures { get; set; } |
||
67 | |||
68 | // Keep a handle to the vehicle actor so it is easy to set parameters on same. |
||
69 | public const string VehicleActorName = "BasicVehicle"; |
||
70 | |||
71 | // Parameters for the hover actor |
||
72 | public const string HoverActorName = "BSPrim.HoverActor"; |
||
73 | // Parameters for the axis lock actor |
||
74 | public const String LockedAxisActorName = "BSPrim.LockedAxis"; |
||
75 | // Parameters for the move to target actor |
||
76 | public const string MoveToTargetActorName = "BSPrim.MoveToTargetActor"; |
||
77 | // Parameters for the setForce and setTorque actors |
||
78 | public const string SetForceActorName = "BSPrim.SetForceActor"; |
||
79 | public const string SetTorqueActorName = "BSPrim.SetTorqueActor"; |
||
80 | |||
81 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, |
||
82 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) |
||
83 | : base(parent_scene, localID, primName, "BSPrim") |
||
84 | { |
||
85 | // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); |
||
86 | _physicsActorType = (int)ActorTypes.Prim; |
||
87 | RawPosition = pos; |
||
88 | _size = size; |
||
89 | Scale = size; // prims are the size the user wants them to be (different for BSCharactes). |
||
90 | RawOrientation = rotation; |
||
91 | _buoyancy = 0f; |
||
92 | RawVelocity = OMV.Vector3.Zero; |
||
93 | _rotationalVelocity = OMV.Vector3.Zero; |
||
94 | BaseShape = pbs; |
||
95 | _isPhysical = pisPhysical; |
||
96 | _isVolumeDetect = false; |
||
97 | |||
98 | // Add a dynamic vehicle to our set of actors that can move this prim. |
||
99 | // PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName)); |
||
100 | |||
101 | _mass = CalculateMass(); |
||
102 | |||
103 | // DetailLog("{0},BSPrim.constructor,call", LocalID); |
||
104 | // do the actual object creation at taint time |
||
105 | PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate() |
||
106 | { |
||
107 | // Make sure the object is being created with some sanity. |
||
108 | ExtremeSanityCheck(true /* inTaintTime */); |
||
109 | |||
110 | CreateGeomAndObject(true); |
||
111 | |||
112 | CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody); |
||
113 | |||
114 | IsInitialized = true; |
||
115 | }); |
||
116 | } |
||
117 | |||
118 | // called when this prim is being destroyed and we should free all the resources |
||
119 | public override void Destroy() |
||
120 | { |
||
121 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); |
||
122 | IsInitialized = false; |
||
123 | |||
124 | base.Destroy(); |
||
125 | |||
126 | // Undo any vehicle properties |
||
127 | this.VehicleType = (int)Vehicle.TYPE_NONE; |
||
128 | |||
129 | PhysScene.TaintedObject(LocalID, "BSPrim.Destroy", delegate() |
||
130 | { |
||
131 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); |
||
132 | // If there are physical body and shape, release my use of same. |
||
133 | PhysScene.Shapes.DereferenceBody(PhysBody, null); |
||
134 | PhysBody.Clear(); |
||
135 | PhysShape.Dereference(PhysScene); |
||
136 | PhysShape = new BSShapeNull(); |
||
137 | }); |
||
138 | } |
||
139 | |||
140 | // No one uses this property. |
||
141 | public override bool Stopped { |
||
142 | get { return false; } |
||
143 | } |
||
144 | public override OMV.Vector3 Size { |
||
145 | get { return _size; } |
||
146 | set { |
||
147 | // We presume the scale and size are the same. If scale must be changed for |
||
148 | // the physical shape, that is done when the geometry is built. |
||
149 | _size = value; |
||
150 | Scale = _size; |
||
151 | ForceBodyShapeRebuild(false); |
||
152 | } |
||
153 | } |
||
154 | |||
155 | public override PrimitiveBaseShape Shape { |
||
156 | set { |
||
157 | BaseShape = value; |
||
158 | PrimAssetState = PrimAssetCondition.Unknown; |
||
159 | ForceBodyShapeRebuild(false); |
||
160 | } |
||
161 | } |
||
162 | public override bool ForceBodyShapeRebuild(bool inTaintTime) |
||
163 | { |
||
164 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ForceBodyShapeRebuild", delegate() |
||
165 | { |
||
166 | _mass = CalculateMass(); // changing the shape changes the mass |
||
167 | CreateGeomAndObject(true); |
||
168 | }); |
||
169 | return true; |
||
170 | } |
||
171 | public override bool Grabbed { |
||
172 | set { _grabbed = value; |
||
173 | } |
||
174 | } |
||
175 | public override bool Selected { |
||
176 | set |
||
177 | { |
||
178 | if (value != _isSelected) |
||
179 | { |
||
180 | _isSelected = value; |
||
181 | PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate() |
||
182 | { |
||
183 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); |
||
184 | SetObjectDynamic(false); |
||
185 | }); |
||
186 | } |
||
187 | } |
||
188 | } |
||
189 | public override bool IsSelected |
||
190 | { |
||
191 | get { return _isSelected; } |
||
192 | } |
||
193 | |||
194 | public override void CrossingFailure() |
||
195 | { |
||
196 | CrossingFailures++; |
||
197 | if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds) |
||
198 | { |
||
199 | base.RaiseOutOfBounds(RawPosition); |
||
200 | } |
||
201 | else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds) |
||
202 | { |
||
203 | m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name); |
||
204 | } |
||
205 | return; |
||
206 | } |
||
207 | |||
208 | // link me to the specified parent |
||
209 | public override void link(PhysicsActor obj) { |
||
210 | } |
||
211 | |||
212 | // delink me from my linkset |
||
213 | public override void delink() { |
||
214 | } |
||
215 | |||
216 | // Set motion values to zero. |
||
217 | // Do it to the properties so the values get set in the physics engine. |
||
218 | // Push the setting of the values to the viewer. |
||
219 | // Called at taint time! |
||
220 | public override void ZeroMotion(bool inTaintTime) |
||
221 | { |
||
222 | RawVelocity = OMV.Vector3.Zero; |
||
223 | _acceleration = OMV.Vector3.Zero; |
||
224 | _rotationalVelocity = OMV.Vector3.Zero; |
||
225 | |||
226 | // Zero some other properties in the physics engine |
||
227 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate() |
||
228 | { |
||
229 | if (PhysBody.HasPhysicalBody) |
||
230 | PhysScene.PE.ClearAllForces(PhysBody); |
||
231 | }); |
||
232 | } |
||
233 | public override void ZeroAngularMotion(bool inTaintTime) |
||
234 | { |
||
235 | _rotationalVelocity = OMV.Vector3.Zero; |
||
236 | // Zero some other properties in the physics engine |
||
237 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate() |
||
238 | { |
||
239 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); |
||
240 | if (PhysBody.HasPhysicalBody) |
||
241 | { |
||
242 | PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); |
||
243 | PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); |
||
244 | } |
||
245 | }); |
||
246 | } |
||
247 | |||
248 | public override void LockAngularMotion(OMV.Vector3 axis) |
||
249 | { |
||
250 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); |
||
251 | |||
252 | // "1" means free, "0" means locked |
||
253 | OMV.Vector3 locking = LockedAxisFree; |
||
254 | if (axis.X != 1) locking.X = 0f; |
||
255 | if (axis.Y != 1) locking.Y = 0f; |
||
256 | if (axis.Z != 1) locking.Z = 0f; |
||
257 | LockedAngularAxis = locking; |
||
258 | |||
259 | EnableActor(LockedAngularAxis != LockedAxisFree, LockedAxisActorName, delegate() |
||
260 | { |
||
261 | return new BSActorLockAxis(PhysScene, this, LockedAxisActorName); |
||
262 | }); |
||
263 | |||
264 | // Update parameters so the new actor's Refresh() action is called at the right time. |
||
265 | PhysScene.TaintedObject(LocalID, "BSPrim.LockAngularMotion", delegate() |
||
266 | { |
||
267 | UpdatePhysicalParameters(); |
||
268 | }); |
||
269 | |||
270 | return; |
||
271 | } |
||
272 | |||
273 | public override OMV.Vector3 Position { |
||
274 | get { |
||
275 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. |
||
276 | // RawPosition = ForcePosition; |
||
277 | return RawPosition; |
||
278 | } |
||
279 | set { |
||
280 | // If the position must be forced into the physics engine, use ForcePosition. |
||
281 | // All positions are given in world positions. |
||
282 | if (RawPosition == value) |
||
283 | { |
||
284 | DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); |
||
285 | return; |
||
286 | } |
||
287 | RawPosition = value; |
||
288 | PositionSanityCheck(false); |
||
289 | |||
290 | PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate() |
||
291 | { |
||
292 | DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); |
||
293 | ForcePosition = RawPosition; |
||
294 | }); |
||
295 | } |
||
296 | } |
||
297 | |||
298 | // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity. |
||
299 | public override OMV.Vector3 ForcePosition { |
||
300 | get { |
||
301 | RawPosition = PhysScene.PE.GetPosition(PhysBody); |
||
302 | return RawPosition; |
||
303 | } |
||
304 | set { |
||
305 | RawPosition = value; |
||
306 | if (PhysBody.HasPhysicalBody) |
||
307 | { |
||
308 | PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); |
||
309 | ActivateIfPhysical(false); |
||
310 | } |
||
311 | } |
||
312 | } |
||
313 | |||
314 | // Check that the current position is sane and, if not, modify the position to make it so. |
||
315 | // Check for being below terrain and being out of bounds. |
||
316 | // Returns 'true' of the position was made sane by some action. |
||
317 | private bool PositionSanityCheck(bool inTaintTime) |
||
318 | { |
||
319 | bool ret = false; |
||
320 | |||
321 | // We don't care where non-physical items are placed |
||
322 | if (!IsPhysicallyActive) |
||
323 | return ret; |
||
324 | |||
325 | if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) |
||
326 | { |
||
327 | // The physical object is out of the known/simulated area. |
||
328 | // Upper levels of code will handle the transition to other areas so, for |
||
329 | // the time, we just ignore the position. |
||
330 | return ret; |
||
331 | } |
||
332 | |||
333 | float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); |
||
334 | OMV.Vector3 upForce = OMV.Vector3.Zero; |
||
335 | float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); |
||
336 | if ((RawPosition.Z + approxSize / 2f) < terrainHeight) |
||
337 | { |
||
338 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); |
||
339 | float targetHeight = terrainHeight + (Size.Z / 2f); |
||
340 | // If the object is below ground it just has to be moved up because pushing will |
||
341 | // not get it through the terrain |
||
342 | RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight); |
||
343 | if (inTaintTime) |
||
344 | { |
||
345 | ForcePosition = RawPosition; |
||
346 | } |
||
347 | // If we are throwing the object around, zero its other forces |
||
348 | ZeroMotion(inTaintTime); |
||
349 | ret = true; |
||
350 | } |
||
351 | |||
352 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
||
353 | { |
||
354 | float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); |
||
355 | // TODO: a floating motor so object will bob in the water |
||
356 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) |
||
357 | { |
||
358 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. |
||
359 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; |
||
360 | |||
361 | // Apply upforce and overcome gravity. |
||
362 | OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity; |
||
363 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, RawPosition, upForce, correctionForce); |
||
364 | AddForce(correctionForce, false, inTaintTime); |
||
365 | ret = true; |
||
366 | } |
||
367 | } |
||
368 | |||
369 | return ret; |
||
370 | } |
||
371 | |||
372 | // Occasionally things will fly off and really get lost. |
||
373 | // Find the wanderers and bring them back. |
||
374 | // Return 'true' if some parameter need some sanity. |
||
375 | private bool ExtremeSanityCheck(bool inTaintTime) |
||
376 | { |
||
377 | bool ret = false; |
||
378 | |||
379 | int wayOverThere = -1000; |
||
380 | int wayOutThere = 10000; |
||
381 | // There have been instances of objects getting thrown way out of bounds and crashing |
||
382 | // the border crossing code. |
||
383 | if ( RawPosition.X < wayOverThere || RawPosition.X > wayOutThere |
||
384 | || RawPosition.Y < wayOverThere || RawPosition.X > wayOutThere |
||
385 | || RawPosition.Z < wayOverThere || RawPosition.X > wayOutThere) |
||
386 | { |
||
387 | RawPosition = new OMV.Vector3(10, 10, 50); |
||
388 | ZeroMotion(inTaintTime); |
||
389 | ret = true; |
||
390 | } |
||
391 | if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocitySquared) |
||
392 | { |
||
393 | RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity); |
||
394 | ret = true; |
||
395 | } |
||
396 | if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) |
||
397 | { |
||
398 | _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); |
||
399 | ret = true; |
||
400 | } |
||
401 | |||
402 | return ret; |
||
403 | } |
||
404 | |||
405 | // Return the effective mass of the object. |
||
406 | // The definition of this call is to return the mass of the prim. |
||
407 | // If the simulator cares about the mass of the linkset, it will sum it itself. |
||
408 | public override float Mass |
||
409 | { |
||
410 | get { return _mass; } |
||
411 | } |
||
412 | // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code) |
||
413 | public virtual float TotalMass |
||
414 | { |
||
415 | get { return _mass; } |
||
416 | } |
||
417 | // used when we only want this prim's mass and not the linkset thing |
||
418 | public override float RawMass { |
||
419 | get { return _mass; } |
||
420 | } |
||
421 | // Set the physical mass to the passed mass. |
||
422 | // Note that this does not change _mass! |
||
423 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) |
||
424 | { |
||
425 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) |
||
426 | { |
||
427 | if (IsStatic) |
||
428 | { |
||
429 | PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity); |
||
430 | Inertia = OMV.Vector3.Zero; |
||
431 | PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia); |
||
432 | PhysScene.PE.UpdateInertiaTensor(PhysBody); |
||
433 | } |
||
434 | else |
||
435 | { |
||
436 | if (inWorld) |
||
437 | { |
||
438 | // Changing interesting properties doesn't change proxy and collision cache |
||
439 | // information. The Bullet solution is to re-add the object to the world |
||
440 | // after parameters are changed. |
||
441 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
||
442 | } |
||
443 | |||
444 | // The computation of mass props requires gravity to be set on the object. |
||
445 | Gravity = ComputeGravity(Buoyancy); |
||
446 | PhysScene.PE.SetGravity(PhysBody, Gravity); |
||
447 | |||
448 | // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG |
||
449 | // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG |
||
450 | |||
451 | Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); |
||
452 | PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia); |
||
453 | PhysScene.PE.UpdateInertiaTensor(PhysBody); |
||
454 | |||
455 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", |
||
456 | LocalID, physMass, Inertia, Gravity, inWorld); |
||
457 | |||
458 | if (inWorld) |
||
459 | { |
||
460 | AddObjectToPhysicalWorld(); |
||
461 | } |
||
462 | } |
||
463 | } |
||
464 | } |
||
465 | |||
466 | // Return what gravity should be set to this very moment |
||
467 | public OMV.Vector3 ComputeGravity(float buoyancy) |
||
468 | { |
||
469 | OMV.Vector3 ret = PhysScene.DefaultGravity; |
||
470 | |||
471 | if (!IsStatic) |
||
472 | { |
||
473 | ret *= (1f - buoyancy); |
||
474 | ret *= GravModifier; |
||
475 | } |
||
476 | |||
477 | return ret; |
||
478 | } |
||
479 | |||
480 | // Is this used? |
||
481 | public override OMV.Vector3 CenterOfMass |
||
482 | { |
||
483 | get { return RawPosition; } |
||
484 | } |
||
485 | |||
486 | // Is this used? |
||
487 | public override OMV.Vector3 GeometricCenter |
||
488 | { |
||
489 | get { return RawPosition; } |
||
490 | } |
||
491 | |||
492 | public override OMV.Vector3 Force { |
||
493 | get { return RawForce; } |
||
494 | set { |
||
495 | RawForce = value; |
||
496 | EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate() |
||
497 | { |
||
498 | return new BSActorSetForce(PhysScene, this, SetForceActorName); |
||
499 | }); |
||
500 | } |
||
501 | } |
||
502 | |||
503 | // Find and return a handle to the current vehicle actor. |
||
504 | // Return 'null' if there is no vehicle actor. |
||
505 | public BSDynamics GetVehicleActor(bool createIfNone) |
||
506 | { |
||
507 | BSDynamics ret = null; |
||
508 | BSActor actor; |
||
509 | if (PhysicalActors.TryGetActor(VehicleActorName, out actor)) |
||
510 | { |
||
511 | ret = actor as BSDynamics; |
||
512 | } |
||
513 | else |
||
514 | { |
||
515 | if (createIfNone) |
||
516 | { |
||
517 | ret = new BSDynamics(PhysScene, this, VehicleActorName); |
||
518 | PhysicalActors.Add(ret.ActorName, ret); |
||
519 | } |
||
520 | } |
||
521 | return ret; |
||
522 | } |
||
523 | |||
524 | public override int VehicleType { |
||
525 | get { |
||
526 | int ret = (int)Vehicle.TYPE_NONE; |
||
527 | BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); |
||
528 | if (vehicleActor != null) |
||
529 | ret = (int)vehicleActor.Type; |
||
530 | return ret; |
||
531 | } |
||
532 | set { |
||
533 | Vehicle type = (Vehicle)value; |
||
534 | |||
535 | PhysScene.TaintedObject(LocalID, "setVehicleType", delegate() |
||
536 | { |
||
537 | // Some vehicle scripts change vehicle type on the fly as an easy way to |
||
538 | // change all the parameters. Like a plane changing to CAR when on the |
||
539 | // ground. In this case, don't want to zero motion. |
||
540 | // ZeroMotion(true /* inTaintTime */); |
||
541 | if (type == Vehicle.TYPE_NONE) |
||
542 | { |
||
543 | // Vehicle type is 'none' so get rid of any actor that may have been allocated. |
||
544 | BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); |
||
545 | if (vehicleActor != null) |
||
546 | { |
||
547 | PhysicalActors.RemoveAndRelease(vehicleActor.ActorName); |
||
548 | } |
||
549 | } |
||
550 | else |
||
551 | { |
||
552 | // Vehicle type is not 'none' so create an actor and set it running. |
||
553 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); |
||
554 | if (vehicleActor != null) |
||
555 | { |
||
556 | vehicleActor.ProcessTypeChange(type); |
||
557 | ActivateIfPhysical(false); |
||
558 | } |
||
559 | } |
||
560 | }); |
||
561 | } |
||
562 | } |
||
563 | public override void VehicleFloatParam(int param, float value) |
||
564 | { |
||
565 | PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate() |
||
566 | { |
||
567 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); |
||
568 | if (vehicleActor != null) |
||
569 | { |
||
570 | vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); |
||
571 | ActivateIfPhysical(false); |
||
572 | } |
||
573 | }); |
||
574 | } |
||
575 | public override void VehicleVectorParam(int param, OMV.Vector3 value) |
||
576 | { |
||
577 | PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate() |
||
578 | { |
||
579 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); |
||
580 | if (vehicleActor != null) |
||
581 | { |
||
582 | vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); |
||
583 | ActivateIfPhysical(false); |
||
584 | } |
||
585 | }); |
||
586 | } |
||
587 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) |
||
588 | { |
||
589 | PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate() |
||
590 | { |
||
591 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); |
||
592 | if (vehicleActor != null) |
||
593 | { |
||
594 | vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); |
||
595 | ActivateIfPhysical(false); |
||
596 | } |
||
597 | }); |
||
598 | } |
||
599 | public override void VehicleFlags(int param, bool remove) |
||
600 | { |
||
601 | PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate() |
||
602 | { |
||
603 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); |
||
604 | if (vehicleActor != null) |
||
605 | { |
||
606 | vehicleActor.ProcessVehicleFlags(param, remove); |
||
607 | } |
||
608 | }); |
||
609 | } |
||
610 | |||
611 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more |
||
612 | public override void SetVolumeDetect(int param) { |
||
613 | bool newValue = (param != 0); |
||
614 | if (_isVolumeDetect != newValue) |
||
615 | { |
||
616 | _isVolumeDetect = newValue; |
||
617 | PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate() |
||
618 | { |
||
619 | // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); |
||
620 | SetObjectDynamic(true); |
||
621 | }); |
||
622 | } |
||
623 | return; |
||
624 | } |
||
625 | public override bool IsVolumeDetect |
||
626 | { |
||
627 | get { return _isVolumeDetect; } |
||
628 | } |
||
629 | public override void SetMaterial(int material) |
||
630 | { |
||
631 | base.SetMaterial(material); |
||
632 | PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate() |
||
633 | { |
||
634 | UpdatePhysicalParameters(); |
||
635 | }); |
||
636 | } |
||
637 | public override float Friction |
||
638 | { |
||
639 | get { return base.Friction; } |
||
640 | set |
||
641 | { |
||
642 | if (base.Friction != value) |
||
643 | { |
||
644 | base.Friction = value; |
||
645 | PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate() |
||
646 | { |
||
647 | UpdatePhysicalParameters(); |
||
648 | }); |
||
649 | } |
||
650 | } |
||
651 | } |
||
652 | public override float Restitution |
||
653 | { |
||
654 | get { return base.Restitution; } |
||
655 | set |
||
656 | { |
||
657 | if (base.Restitution != value) |
||
658 | { |
||
659 | base.Restitution = value; |
||
660 | PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate() |
||
661 | { |
||
662 | UpdatePhysicalParameters(); |
||
663 | }); |
||
664 | } |
||
665 | } |
||
666 | } |
||
667 | // The simulator/viewer keep density as 100kg/m3. |
||
668 | // Remember to use BSParam.DensityScaleFactor to create the physical density. |
||
669 | public override float Density |
||
670 | { |
||
671 | get { return base.Density; } |
||
672 | set |
||
673 | { |
||
674 | if (base.Density != value) |
||
675 | { |
||
676 | base.Density = value; |
||
677 | PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate() |
||
678 | { |
||
679 | UpdatePhysicalParameters(); |
||
680 | }); |
||
681 | } |
||
682 | } |
||
683 | } |
||
684 | public override float GravModifier |
||
685 | { |
||
686 | get { return base.GravModifier; } |
||
687 | set |
||
688 | { |
||
689 | if (base.GravModifier != value) |
||
690 | { |
||
691 | base.GravModifier = value; |
||
692 | PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate() |
||
693 | { |
||
694 | UpdatePhysicalParameters(); |
||
695 | }); |
||
696 | } |
||
697 | } |
||
698 | } |
||
699 | public override OMV.Vector3 Velocity { |
||
700 | get { return RawVelocity; } |
||
701 | set { |
||
702 | RawVelocity = value; |
||
703 | PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate() |
||
704 | { |
||
705 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity); |
||
706 | ForceVelocity = RawVelocity; |
||
707 | }); |
||
708 | } |
||
709 | } |
||
710 | public override OMV.Vector3 ForceVelocity { |
||
711 | get { return RawVelocity; } |
||
712 | set { |
||
713 | PhysScene.AssertInTaintTime("BSPrim.ForceVelocity"); |
||
714 | |||
715 | RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); |
||
716 | if (PhysBody.HasPhysicalBody) |
||
717 | { |
||
718 | DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity); |
||
719 | PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); |
||
720 | ActivateIfPhysical(false); |
||
721 | } |
||
722 | } |
||
723 | } |
||
724 | public override OMV.Vector3 Torque { |
||
725 | get { return RawTorque; } |
||
726 | set { |
||
727 | RawTorque = value; |
||
728 | EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate() |
||
729 | { |
||
730 | return new BSActorSetTorque(PhysScene, this, SetTorqueActorName); |
||
731 | }); |
||
732 | DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque); |
||
733 | } |
||
734 | } |
||
735 | public override OMV.Vector3 Acceleration { |
||
736 | get { return _acceleration; } |
||
737 | set { _acceleration = value; } |
||
738 | } |
||
739 | |||
740 | public override OMV.Quaternion Orientation { |
||
741 | get { |
||
742 | return RawOrientation; |
||
743 | } |
||
744 | set { |
||
745 | if (RawOrientation == value) |
||
746 | return; |
||
747 | RawOrientation = value; |
||
748 | |||
749 | PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate() |
||
750 | { |
||
751 | ForceOrientation = RawOrientation; |
||
752 | }); |
||
753 | } |
||
754 | } |
||
755 | // Go directly to Bullet to get/set the value. |
||
756 | public override OMV.Quaternion ForceOrientation |
||
757 | { |
||
758 | get |
||
759 | { |
||
760 | RawOrientation = PhysScene.PE.GetOrientation(PhysBody); |
||
761 | return RawOrientation; |
||
762 | } |
||
763 | set |
||
764 | { |
||
765 | RawOrientation = value; |
||
766 | if (PhysBody.HasPhysicalBody) |
||
767 | PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); |
||
768 | } |
||
769 | } |
||
770 | public override int PhysicsActorType { |
||
771 | get { return _physicsActorType; } |
||
772 | set { _physicsActorType = value; } |
||
773 | } |
||
774 | public override bool IsPhysical { |
||
775 | get { return _isPhysical; } |
||
776 | set { |
||
777 | if (_isPhysical != value) |
||
778 | { |
||
779 | _isPhysical = value; |
||
780 | PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate() |
||
781 | { |
||
782 | DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); |
||
783 | SetObjectDynamic(true); |
||
784 | // whether phys-to-static or static-to-phys, the object is not moving. |
||
785 | ZeroMotion(true); |
||
786 | |||
787 | }); |
||
788 | } |
||
789 | } |
||
790 | } |
||
791 | |||
792 | // An object is static (does not move) if selected or not physical |
||
793 | public override bool IsStatic |
||
794 | { |
||
795 | get { return _isSelected || !IsPhysical; } |
||
796 | } |
||
797 | |||
798 | // An object is solid if it's not phantom and if it's not doing VolumeDetect |
||
799 | public override bool IsSolid |
||
800 | { |
||
801 | get { return !IsPhantom && !_isVolumeDetect; } |
||
802 | } |
||
803 | |||
804 | // The object is moving and is actively being dynamic in the physical world |
||
805 | public override bool IsPhysicallyActive |
||
806 | { |
||
807 | get { return !_isSelected && IsPhysical; } |
||
808 | } |
||
809 | |||
810 | // Make gravity work if the object is physical and not selected |
||
811 | // Called at taint-time!! |
||
812 | private void SetObjectDynamic(bool forceRebuild) |
||
813 | { |
||
814 | // Recreate the physical object if necessary |
||
815 | CreateGeomAndObject(forceRebuild); |
||
816 | } |
||
817 | |||
818 | // Convert the simulator's physical properties into settings on BulletSim objects. |
||
819 | // There are four flags we're interested in: |
||
820 | // IsStatic: Object does not move, otherwise the object has mass and moves |
||
821 | // isSolid: other objects bounce off of this object |
||
822 | // isVolumeDetect: other objects pass through but can generate collisions |
||
823 | // collisionEvents: whether this object returns collision events |
||
824 | // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters. |
||
825 | public virtual void UpdatePhysicalParameters() |
||
826 | { |
||
827 | if (!PhysBody.HasPhysicalBody) |
||
828 | { |
||
829 | // This would only happen if updates are called for during initialization when the body is not set up yet. |
||
830 | // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); |
||
831 | return; |
||
832 | } |
||
833 | |||
834 | // Mangling all the physical properties requires the object not be in the physical world. |
||
835 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). |
||
836 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
||
837 | |||
838 | // Set up the object physicalness (does gravity and collisions move this object) |
||
839 | MakeDynamic(IsStatic); |
||
840 | |||
841 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) |
||
842 | PhysicalActors.Refresh(); |
||
843 | |||
844 | // Arrange for collision events if the simulator wants them |
||
845 | EnableCollisions(SubscribedEvents()); |
||
846 | |||
847 | // Make solid or not (do things bounce off or pass through this object). |
||
848 | MakeSolid(IsSolid); |
||
849 | |||
850 | AddObjectToPhysicalWorld(); |
||
851 | |||
852 | // Rebuild its shape |
||
853 | PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); |
||
854 | |||
855 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", |
||
856 | LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), |
||
857 | CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); |
||
858 | } |
||
859 | |||
860 | // "Making dynamic" means changing to and from static. |
||
861 | // When static, gravity does not effect the object and it is fixed in space. |
||
862 | // When dynamic, the object can fall and be pushed by others. |
||
863 | // This is independent of its 'solidness' which controls what passes through |
||
864 | // this object and what interacts with it. |
||
865 | protected virtual void MakeDynamic(bool makeStatic) |
||
866 | { |
||
867 | if (makeStatic) |
||
868 | { |
||
869 | // Become a Bullet 'static' object type |
||
870 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); |
||
871 | // Stop all movement |
||
872 | ZeroMotion(true); |
||
873 | |||
874 | // Set various physical properties so other object interact properly |
||
875 | PhysScene.PE.SetFriction(PhysBody, Friction); |
||
876 | PhysScene.PE.SetRestitution(PhysBody, Restitution); |
||
877 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
||
878 | |||
879 | // Mass is zero which disables a bunch of physics stuff in Bullet |
||
880 | UpdatePhysicalMassProperties(0f, false); |
||
881 | // Set collision detection parameters |
||
882 | if (BSParam.CcdMotionThreshold > 0f) |
||
883 | { |
||
884 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
||
885 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
||
886 | } |
||
887 | |||
888 | // The activation state is 'disabled' so Bullet will not try to act on it. |
||
889 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); |
||
890 | // Start it out sleeping and physical actions could wake it up. |
||
891 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); |
||
892 | |||
893 | // This collides like a static object |
||
894 | PhysBody.collisionType = CollisionType.Static; |
||
895 | } |
||
896 | else |
||
897 | { |
||
898 | // Not a Bullet static object |
||
899 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); |
||
900 | |||
901 | // Set various physical properties so other object interact properly |
||
902 | PhysScene.PE.SetFriction(PhysBody, Friction); |
||
903 | PhysScene.PE.SetRestitution(PhysBody, Restitution); |
||
904 | // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); |
||
905 | |||
906 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 |
||
907 | // Since this can be called multiple times, only zero forces when becoming physical |
||
908 | // PhysicsScene.PE.ClearAllForces(BSBody); |
||
909 | |||
910 | // For good measure, make sure the transform is set through to the motion state |
||
911 | ForcePosition = RawPosition; |
||
912 | ForceVelocity = RawVelocity; |
||
913 | ForceRotationalVelocity = _rotationalVelocity; |
||
914 | |||
915 | // A dynamic object has mass |
||
916 | UpdatePhysicalMassProperties(RawMass, false); |
||
917 | |||
918 | // Set collision detection parameters |
||
919 | if (BSParam.CcdMotionThreshold > 0f) |
||
920 | { |
||
921 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
||
922 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
||
923 | } |
||
924 | |||
925 | // Various values for simulation limits |
||
926 | PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); |
||
927 | PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); |
||
928 | PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); |
||
929 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
||
930 | |||
931 | // This collides like an object. |
||
932 | PhysBody.collisionType = CollisionType.Dynamic; |
||
933 | |||
934 | // Force activation of the object so Bullet will act on it. |
||
935 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. |
||
936 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); |
||
937 | } |
||
938 | } |
||
939 | |||
940 | // "Making solid" means that other object will not pass through this object. |
||
941 | // To make transparent, we create a Bullet ghost object. |
||
942 | // Note: This expects to be called from the UpdatePhysicalParameters() routine as |
||
943 | // the functions after this one set up the state of a possibly newly created collision body. |
||
944 | private void MakeSolid(bool makeSolid) |
||
945 | { |
||
946 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody); |
||
947 | if (makeSolid) |
||
948 | { |
||
949 | // Verify the previous code created the correct shape for this type of thing. |
||
950 | if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0) |
||
951 | { |
||
952 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); |
||
953 | } |
||
954 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
||
955 | } |
||
956 | else |
||
957 | { |
||
958 | if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0) |
||
959 | { |
||
960 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); |
||
961 | } |
||
962 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
||
963 | |||
964 | // Change collision info from a static object to a ghosty collision object |
||
965 | PhysBody.collisionType = CollisionType.VolumeDetect; |
||
966 | } |
||
967 | } |
||
968 | |||
969 | // Turn on or off the flag controlling whether collision events are returned to the simulator. |
||
970 | private void EnableCollisions(bool wantsCollisionEvents) |
||
971 | { |
||
972 | if (wantsCollisionEvents) |
||
973 | { |
||
974 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
||
975 | } |
||
976 | else |
||
977 | { |
||
978 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
||
979 | } |
||
980 | } |
||
981 | |||
982 | // Add me to the physical world. |
||
983 | // Object MUST NOT already be in the world. |
||
984 | // This routine exists because some assorted properties get mangled by adding to the world. |
||
985 | internal void AddObjectToPhysicalWorld() |
||
986 | { |
||
987 | if (PhysBody.HasPhysicalBody) |
||
988 | { |
||
989 | PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); |
||
990 | } |
||
991 | else |
||
992 | { |
||
993 | m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID); |
||
994 | DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType); |
||
995 | } |
||
996 | } |
||
997 | |||
998 | // prims don't fly |
||
999 | public override bool Flying { |
||
1000 | get { return _flying; } |
||
1001 | set { |
||
1002 | _flying = value; |
||
1003 | } |
||
1004 | } |
||
1005 | public override bool SetAlwaysRun { |
||
1006 | get { return _setAlwaysRun; } |
||
1007 | set { _setAlwaysRun = value; } |
||
1008 | } |
||
1009 | public override bool ThrottleUpdates { |
||
1010 | get { return _throttleUpdates; } |
||
1011 | set { _throttleUpdates = value; } |
||
1012 | } |
||
1013 | public bool IsPhantom { |
||
1014 | get { |
||
1015 | // SceneObjectPart removes phantom objects from the physics scene |
||
1016 | // so, although we could implement touching and such, we never |
||
1017 | // are invoked as a phantom object |
||
1018 | return false; |
||
1019 | } |
||
1020 | } |
||
1021 | public override bool FloatOnWater { |
||
1022 | set { |
||
1023 | _floatOnWater = value; |
||
1024 | PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate() |
||
1025 | { |
||
1026 | if (_floatOnWater) |
||
1027 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
||
1028 | else |
||
1029 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
||
1030 | }); |
||
1031 | } |
||
1032 | } |
||
1033 | public override OMV.Vector3 RotationalVelocity { |
||
1034 | get { |
||
1035 | return _rotationalVelocity; |
||
1036 | } |
||
1037 | set { |
||
1038 | _rotationalVelocity = value; |
||
1039 | Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); |
||
1040 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); |
||
1041 | PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate() |
||
1042 | { |
||
1043 | ForceRotationalVelocity = _rotationalVelocity; |
||
1044 | }); |
||
1045 | } |
||
1046 | } |
||
1047 | public override OMV.Vector3 ForceRotationalVelocity { |
||
1048 | get { |
||
1049 | return _rotationalVelocity; |
||
1050 | } |
||
1051 | set { |
||
1052 | _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity); |
||
1053 | if (PhysBody.HasPhysicalBody) |
||
1054 | { |
||
1055 | DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); |
||
1056 | PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); |
||
1057 | // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); |
||
1058 | ActivateIfPhysical(false); |
||
1059 | } |
||
1060 | } |
||
1061 | } |
||
1062 | public override bool Kinematic { |
||
1063 | get { return _kinematic; } |
||
1064 | set { _kinematic = value; |
||
1065 | // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); |
||
1066 | } |
||
1067 | } |
||
1068 | public override float Buoyancy { |
||
1069 | get { return _buoyancy; } |
||
1070 | set { |
||
1071 | _buoyancy = value; |
||
1072 | PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate() |
||
1073 | { |
||
1074 | ForceBuoyancy = _buoyancy; |
||
1075 | }); |
||
1076 | } |
||
1077 | } |
||
1078 | public override float ForceBuoyancy { |
||
1079 | get { return _buoyancy; } |
||
1080 | set { |
||
1081 | _buoyancy = value; |
||
1082 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
||
1083 | // Force the recalculation of the various inertia,etc variables in the object |
||
1084 | UpdatePhysicalMassProperties(RawMass, true); |
||
1085 | DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity); |
||
1086 | ActivateIfPhysical(false); |
||
1087 | } |
||
1088 | } |
||
1089 | |||
1090 | public override bool PIDActive { |
||
1091 | set { |
||
1092 | base.MoveToTargetActive = value; |
||
1093 | EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate() |
||
1094 | { |
||
1095 | return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName); |
||
1096 | }); |
||
1097 | } |
||
1098 | } |
||
1099 | |||
1100 | public override OMV.Vector3 PIDTarget |
||
1101 | { |
||
1102 | set |
||
1103 | { |
||
1104 | base.PIDTarget = value; |
||
1105 | BSActor actor; |
||
1106 | if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor)) |
||
1107 | { |
||
1108 | // if the actor exists, tell it to refresh its values. |
||
1109 | actor.Refresh(); |
||
1110 | } |
||
1111 | |||
1112 | } |
||
1113 | } |
||
1114 | // Used for llSetHoverHeight and maybe vehicle height |
||
1115 | // Hover Height will override MoveTo target's Z |
||
1116 | public override bool PIDHoverActive { |
||
1117 | set { |
||
1118 | base.HoverActive = value; |
||
1119 | EnableActor(HoverActive, HoverActorName, delegate() |
||
1120 | { |
||
1121 | return new BSActorHover(PhysScene, this, HoverActorName); |
||
1122 | }); |
||
1123 | } |
||
1124 | } |
||
1125 | |||
1126 | public override void AddForce(OMV.Vector3 force, bool pushforce) { |
||
1127 | // Per documentation, max force is limited. |
||
1128 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); |
||
1129 | |||
1130 | // Since this force is being applied in only one step, make this a force per second. |
||
1131 | addForce /= PhysScene.LastTimeStep; |
||
1132 | AddForce(addForce, pushforce, false /* inTaintTime */); |
||
1133 | } |
||
1134 | |||
1135 | // Applying a force just adds this to the total force on the object. |
||
1136 | // This added force will only last the next simulation tick. |
||
1137 | public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
||
1138 | // for an object, doesn't matter if force is a pushforce or not |
||
1139 | if (IsPhysicallyActive) |
||
1140 | { |
||
1141 | if (force.IsFinite()) |
||
1142 | { |
||
1143 | // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); |
||
1144 | |||
1145 | OMV.Vector3 addForce = force; |
||
1146 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate() |
||
1147 | { |
||
1148 | // Bullet adds this central force to the total force for this tick. |
||
1149 | // Deep down in Bullet: |
||
1150 | // linearVelocity += totalForce / mass * timeStep; |
||
1151 | DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); |
||
1152 | if (PhysBody.HasPhysicalBody) |
||
1153 | { |
||
1154 | PhysScene.PE.ApplyCentralForce(PhysBody, addForce); |
||
1155 | ActivateIfPhysical(false); |
||
1156 | } |
||
1157 | }); |
||
1158 | } |
||
1159 | else |
||
1160 | { |
||
1161 | m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); |
||
1162 | return; |
||
1163 | } |
||
1164 | } |
||
1165 | } |
||
1166 | |||
1167 | public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) { |
||
1168 | // for an object, doesn't matter if force is a pushforce or not |
||
1169 | if (!IsPhysicallyActive) |
||
1170 | { |
||
1171 | if (impulse.IsFinite()) |
||
1172 | { |
||
1173 | OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); |
||
1174 | // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); |
||
1175 | |||
1176 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate() |
||
1177 | { |
||
1178 | // Bullet adds this impulse immediately to the velocity |
||
1179 | DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); |
||
1180 | if (PhysBody.HasPhysicalBody) |
||
1181 | { |
||
1182 | PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); |
||
1183 | ActivateIfPhysical(false); |
||
1184 | } |
||
1185 | }); |
||
1186 | } |
||
1187 | else |
||
1188 | { |
||
1189 | m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID); |
||
1190 | return; |
||
1191 | } |
||
1192 | } |
||
1193 | } |
||
1194 | |||
1195 | // BSPhysObject.AddAngularForce() |
||
1196 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) |
||
1197 | { |
||
1198 | if (force.IsFinite()) |
||
1199 | { |
||
1200 | OMV.Vector3 angForce = force; |
||
1201 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate() |
||
1202 | { |
||
1203 | if (PhysBody.HasPhysicalBody) |
||
1204 | { |
||
1205 | DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); |
||
1206 | PhysScene.PE.ApplyTorque(PhysBody, angForce); |
||
1207 | ActivateIfPhysical(false); |
||
1208 | } |
||
1209 | }); |
||
1210 | } |
||
1211 | else |
||
1212 | { |
||
1213 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); |
||
1214 | return; |
||
1215 | } |
||
1216 | } |
||
1217 | |||
1218 | // A torque impulse. |
||
1219 | // ApplyTorqueImpulse adds torque directly to the angularVelocity. |
||
1220 | // AddAngularForce accumulates the force and applied it to the angular velocity all at once. |
||
1221 | // Computed as: angularVelocity += impulse * inertia; |
||
1222 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) |
||
1223 | { |
||
1224 | OMV.Vector3 applyImpulse = impulse; |
||
1225 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate() |
||
1226 | { |
||
1227 | if (PhysBody.HasPhysicalBody) |
||
1228 | { |
||
1229 | PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); |
||
1230 | ActivateIfPhysical(false); |
||
1231 | } |
||
1232 | }); |
||
1233 | } |
||
1234 | |||
1235 | public override void SetMomentum(OMV.Vector3 momentum) { |
||
1236 | // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); |
||
1237 | } |
||
1238 | #region Mass Calculation |
||
1239 | |||
1240 | private float CalculateMass() |
||
1241 | { |
||
1242 | float volume = _size.X * _size.Y * _size.Z; // default |
||
1243 | float tmp; |
||
1244 | |||
1245 | float returnMass = 0; |
||
1246 | float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f; |
||
1247 | float hollowVolume = hollowAmount * hollowAmount; |
||
1248 | |||
1249 | switch (BaseShape.ProfileShape) |
||
1250 | { |
||
1251 | case ProfileShape.Square: |
||
1252 | // default box |
||
1253 | |||
1254 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) |
||
1255 | { |
||
1256 | if (hollowAmount > 0.0) |
||
1257 | { |
||
1258 | switch (BaseShape.HollowShape) |
||
1259 | { |
||
1260 | case HollowShape.Square: |
||
1261 | case HollowShape.Same: |
||
1262 | break; |
||
1263 | |||
1264 | case HollowShape.Circle: |
||
1265 | |||
1266 | hollowVolume *= 0.78539816339f; |
||
1267 | break; |
||
1268 | |||
1269 | case HollowShape.Triangle: |
||
1270 | |||
1271 | hollowVolume *= (0.5f * .5f); |
||
1272 | break; |
||
1273 | |||
1274 | default: |
||
1275 | hollowVolume = 0; |
||
1276 | break; |
||
1277 | } |
||
1278 | volume *= (1.0f - hollowVolume); |
||
1279 | } |
||
1280 | } |
||
1281 | |||
1282 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) |
||
1283 | { |
||
1284 | //a tube |
||
1285 | |||
1286 | volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX); |
||
1287 | tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY); |
||
1288 | volume -= volume*tmp*tmp; |
||
1289 | |||
1290 | if (hollowAmount > 0.0) |
||
1291 | { |
||
1292 | hollowVolume *= hollowAmount; |
||
1293 | |||
1294 | switch (BaseShape.HollowShape) |
||
1295 | { |
||
1296 | case HollowShape.Square: |
||
1297 | case HollowShape.Same: |
||
1298 | break; |
||
1299 | |||
1300 | case HollowShape.Circle: |
||
1301 | hollowVolume *= 0.78539816339f;; |
||
1302 | break; |
||
1303 | |||
1304 | case HollowShape.Triangle: |
||
1305 | hollowVolume *= 0.5f * 0.5f; |
||
1306 | break; |
||
1307 | default: |
||
1308 | hollowVolume = 0; |
||
1309 | break; |
||
1310 | } |
||
1311 | volume *= (1.0f - hollowVolume); |
||
1312 | } |
||
1313 | } |
||
1314 | |||
1315 | break; |
||
1316 | |||
1317 | case ProfileShape.Circle: |
||
1318 | |||
1319 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) |
||
1320 | { |
||
1321 | volume *= 0.78539816339f; // elipse base |
||
1322 | |||
1323 | if (hollowAmount > 0.0) |
||
1324 | { |
||
1325 | switch (BaseShape.HollowShape) |
||
1326 | { |
||
1327 | case HollowShape.Same: |
||
1328 | case HollowShape.Circle: |
||
1329 | break; |
||
1330 | |||
1331 | case HollowShape.Square: |
||
1332 | hollowVolume *= 0.5f * 2.5984480504799f; |
||
1333 | break; |
||
1334 | |||
1335 | case HollowShape.Triangle: |
||
1336 | hollowVolume *= .5f * 1.27323954473516f; |
||
1337 | break; |
||
1338 | |||
1339 | default: |
||
1340 | hollowVolume = 0; |
||
1341 | break; |
||
1342 | } |
||
1343 | volume *= (1.0f - hollowVolume); |
||
1344 | } |
||
1345 | } |
||
1346 | |||
1347 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) |
||
1348 | { |
||
1349 | volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX); |
||
1350 | tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); |
||
1351 | volume *= (1.0f - tmp * tmp); |
||
1352 | |||
1353 | if (hollowAmount > 0.0) |
||
1354 | { |
||
1355 | |||
1356 | // calculate the hollow volume by it's shape compared to the prim shape |
||
1357 | hollowVolume *= hollowAmount; |
||
1358 | |||
1359 | switch (BaseShape.HollowShape) |
||
1360 | { |
||
1361 | case HollowShape.Same: |
||
1362 | case HollowShape.Circle: |
||
1363 | break; |
||
1364 | |||
1365 | case HollowShape.Square: |
||
1366 | hollowVolume *= 0.5f * 2.5984480504799f; |
||
1367 | break; |
||
1368 | |||
1369 | case HollowShape.Triangle: |
||
1370 | hollowVolume *= .5f * 1.27323954473516f; |
||
1371 | break; |
||
1372 | |||
1373 | default: |
||
1374 | hollowVolume = 0; |
||
1375 | break; |
||
1376 | } |
||
1377 | volume *= (1.0f - hollowVolume); |
||
1378 | } |
||
1379 | } |
||
1380 | break; |
||
1381 | |||
1382 | case ProfileShape.HalfCircle: |
||
1383 | if (BaseShape.PathCurve == (byte)Extrusion.Curve1) |
||
1384 | { |
||
1385 | volume *= 0.52359877559829887307710723054658f; |
||
1386 | } |
||
1387 | break; |
||
1388 | |||
1389 | case ProfileShape.EquilateralTriangle: |
||
1390 | |||
1391 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) |
||
1392 | { |
||
1393 | volume *= 0.32475953f; |
||
1394 | |||
1395 | if (hollowAmount > 0.0) |
||
1396 | { |
||
1397 | |||
1398 | // calculate the hollow volume by it's shape compared to the prim shape |
||
1399 | switch (BaseShape.HollowShape) |
||
1400 | { |
||
1401 | case HollowShape.Same: |
||
1402 | case HollowShape.Triangle: |
||
1403 | hollowVolume *= .25f; |
||
1404 | break; |
||
1405 | |||
1406 | case HollowShape.Square: |
||
1407 | hollowVolume *= 0.499849f * 3.07920140172638f; |
||
1408 | break; |
||
1409 | |||
1410 | case HollowShape.Circle: |
||
1411 | // Hollow shape is a perfect cyllinder in respect to the cube's scale |
||
1412 | // Cyllinder hollow volume calculation |
||
1413 | |||
1414 | hollowVolume *= 0.1963495f * 3.07920140172638f; |
||
1415 | break; |
||
1416 | |||
1417 | default: |
||
1418 | hollowVolume = 0; |
||
1419 | break; |
||
1420 | } |
||
1421 | volume *= (1.0f - hollowVolume); |
||
1422 | } |
||
1423 | } |
||
1424 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) |
||
1425 | { |
||
1426 | volume *= 0.32475953f; |
||
1427 | volume *= 0.01f * (float)(200 - BaseShape.PathScaleX); |
||
1428 | tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); |
||
1429 | volume *= (1.0f - tmp * tmp); |
||
1430 | |||
1431 | if (hollowAmount > 0.0) |
||
1432 | { |
||
1433 | |||
1434 | hollowVolume *= hollowAmount; |
||
1435 | |||
1436 | switch (BaseShape.HollowShape) |
||
1437 | { |
||
1438 | case HollowShape.Same: |
||
1439 | case HollowShape.Triangle: |
||
1440 | hollowVolume *= .25f; |
||
1441 | break; |
||
1442 | |||
1443 | case HollowShape.Square: |
||
1444 | hollowVolume *= 0.499849f * 3.07920140172638f; |
||
1445 | break; |
||
1446 | |||
1447 | case HollowShape.Circle: |
||
1448 | |||
1449 | hollowVolume *= 0.1963495f * 3.07920140172638f; |
||
1450 | break; |
||
1451 | |||
1452 | default: |
||
1453 | hollowVolume = 0; |
||
1454 | break; |
||
1455 | } |
||
1456 | volume *= (1.0f - hollowVolume); |
||
1457 | } |
||
1458 | } |
||
1459 | break; |
||
1460 | |||
1461 | default: |
||
1462 | break; |
||
1463 | } |
||
1464 | |||
1465 | |||
1466 | |||
1467 | float taperX1; |
||
1468 | float taperY1; |
||
1469 | float taperX; |
||
1470 | float taperY; |
||
1471 | float pathBegin; |
||
1472 | float pathEnd; |
||
1473 | float profileBegin; |
||
1474 | float profileEnd; |
||
1475 | |||
1476 | if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible) |
||
1477 | { |
||
1478 | taperX1 = BaseShape.PathScaleX * 0.01f; |
||
1479 | if (taperX1 > 1.0f) |
||
1480 | taperX1 = 2.0f - taperX1; |
||
1481 | taperX = 1.0f - taperX1; |
||
1482 | |||
1483 | taperY1 = BaseShape.PathScaleY * 0.01f; |
||
1484 | if (taperY1 > 1.0f) |
||
1485 | taperY1 = 2.0f - taperY1; |
||
1486 | taperY = 1.0f - taperY1; |
||
1487 | } |
||
1488 | else |
||
1489 | { |
||
1490 | taperX = BaseShape.PathTaperX * 0.01f; |
||
1491 | if (taperX < 0.0f) |
||
1492 | taperX = -taperX; |
||
1493 | taperX1 = 1.0f - taperX; |
||
1494 | |||
1495 | taperY = BaseShape.PathTaperY * 0.01f; |
||
1496 | if (taperY < 0.0f) |
||
1497 | taperY = -taperY; |
||
1498 | taperY1 = 1.0f - taperY; |
||
1499 | |||
1500 | } |
||
1501 | |||
1502 | |||
1503 | volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); |
||
1504 | |||
1505 | pathBegin = (float)BaseShape.PathBegin * 2.0e-5f; |
||
1506 | pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f; |
||
1507 | volume *= (pathEnd - pathBegin); |
||
1508 | |||
1509 | // this is crude aproximation |
||
1510 | profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f; |
||
1511 | profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; |
||
1512 | volume *= (profileEnd - profileBegin); |
||
1513 | |||
1514 | returnMass = Density * BSParam.DensityScaleFactor * volume; |
||
1515 | |||
1516 | returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); |
||
1517 | // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass); |
||
1518 | DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}", |
||
1519 | LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size); |
||
1520 | |||
1521 | return returnMass; |
||
1522 | }// end CalculateMass |
||
1523 | #endregion Mass Calculation |
||
1524 | |||
1525 | // Rebuild the geometry and object. |
||
1526 | // This is called when the shape changes so we need to recreate the mesh/hull. |
||
1527 | // Called at taint-time!!! |
||
1528 | public void CreateGeomAndObject(bool forceRebuild) |
||
1529 | { |
||
1530 | // Create the correct physical representation for this type of object. |
||
1531 | // Updates base.PhysBody and base.PhysShape with the new information. |
||
1532 | // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. |
||
1533 | PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape) |
||
1534 | { |
||
1535 | // Called if the current prim body is about to be destroyed. |
||
1536 | // Remove all the physical dependencies on the old body. |
||
1537 | // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) |
||
1538 | // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints. |
||
1539 | RemoveDependencies(); |
||
1540 | }); |
||
1541 | |||
1542 | // Make sure the properties are set on the new object |
||
1543 | UpdatePhysicalParameters(); |
||
1544 | return; |
||
1545 | } |
||
1546 | |||
1547 | // Called at taint-time |
||
1548 | protected virtual void RemoveDependencies() |
||
1549 | { |
||
1550 | PhysicalActors.RemoveDependencies(); |
||
1551 | } |
||
1552 | |||
1553 | #region Extension |
||
1554 | public override object Extension(string pFunct, params object[] pParams) |
||
1555 | { |
||
1556 | DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct); |
||
1557 | object ret = null; |
||
1558 | switch (pFunct) |
||
1559 | { |
||
1560 | default: |
||
1561 | ret = base.Extension(pFunct, pParams); |
||
1562 | break; |
||
1563 | } |
||
1564 | return ret; |
||
1565 | } |
||
1566 | #endregion // Extension |
||
1567 | |||
1568 | // The physics engine says that properties have updated. Update same and inform |
||
1569 | // the world that things have changed. |
||
1570 | // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims. |
||
1571 | // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position. |
||
1572 | public override void UpdateProperties(EntityProperties entprop) |
||
1573 | { |
||
1574 | // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. |
||
1575 | TriggerPreUpdatePropertyAction(ref entprop); |
||
1576 | |||
1577 | // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG |
||
1578 | |||
1579 | // Assign directly to the local variables so the normal set actions do not happen |
||
1580 | RawPosition = entprop.Position; |
||
1581 | RawOrientation = entprop.Rotation; |
||
1582 | // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be |
||
1583 | // very sensitive to velocity changes. |
||
1584 | if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold)) |
||
1585 | RawVelocity = entprop.Velocity; |
||
1586 | _acceleration = entprop.Acceleration; |
||
1587 | _rotationalVelocity = entprop.RotationalVelocity; |
||
1588 | |||
1589 | // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG |
||
1590 | |||
1591 | // The sanity check can change the velocity and/or position. |
||
1592 | if (PositionSanityCheck(true /* inTaintTime */ )) |
||
1593 | { |
||
1594 | entprop.Position = RawPosition; |
||
1595 | entprop.Velocity = RawVelocity; |
||
1596 | entprop.RotationalVelocity = _rotationalVelocity; |
||
1597 | entprop.Acceleration = _acceleration; |
||
1598 | } |
||
1599 | |||
1600 | OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG |
||
1601 | DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction); |
||
1602 | |||
1603 | // remember the current and last set values |
||
1604 | LastEntityProperties = CurrentEntityProperties; |
||
1605 | CurrentEntityProperties = entprop; |
||
1606 | |||
1607 | PhysScene.PostUpdate(this); |
||
1608 | } |
||
1609 | } |
||
1610 | } |