diff options
Merge branch 'ubitwork' of ssh://3dhosting.de/var/git/careminster into ubitwork
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 1392 |
1 files changed, 731 insertions, 661 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 9c20004..2b3fa25 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -24,6 +24,7 @@ | |||
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 | using System; | 28 | using System; |
28 | using System.Reflection; | 29 | using System.Reflection; |
29 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
@@ -36,32 +37,17 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet; | |||
36 | 37 | ||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | 38 | namespace OpenSim.Region.Physics.BulletSPlugin |
38 | { | 39 | { |
40 | |||
39 | [Serializable] | 41 | [Serializable] |
40 | public sealed class BSPrim : PhysicsActor | 42 | public sealed class BSPrim : BSPhysObject |
41 | { | 43 | { |
42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
43 | private static readonly string LogHeader = "[BULLETS PRIM]"; | 45 | private static readonly string LogHeader = "[BULLETS PRIM]"; |
44 | 46 | ||
45 | private void DebugLog(string mm, params Object[] xx) { if (_scene.ShouldDebugLog) m_log.DebugFormat(mm, xx); } | 47 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. |
46 | 48 | // Often Scale is unity because the meshmerizer will apply _size when creating the mesh. | |
47 | private IMesh _mesh; | ||
48 | private PrimitiveBaseShape _pbs; | ||
49 | private ShapeData.PhysicsShapeType _shapeType; | ||
50 | private ulong _meshKey; | ||
51 | private ulong _hullKey; | ||
52 | private List<ConvexResult> _hulls; | ||
53 | |||
54 | private BSScene _scene; | ||
55 | public BSScene Scene { get { return _scene; } } | ||
56 | private String _avName; | ||
57 | private uint _localID = 0; | ||
58 | |||
59 | // _size is what the user passed. _scale is what we pass to the physics engine with the mesh. | ||
60 | // Often _scale is unity because the meshmerizer will apply _size when creating the mesh. | ||
61 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user | 49 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user |
62 | private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer | ||
63 | 50 | ||
64 | private bool _stopped; | ||
65 | private bool _grabbed; | 51 | private bool _grabbed; |
66 | private bool _isSelected; | 52 | private bool _isSelected; |
67 | private bool _isVolumeDetect; | 53 | private bool _isVolumeDetect; |
@@ -89,25 +75,6 @@ public sealed class BSPrim : PhysicsActor | |||
89 | private bool _kinematic; | 75 | private bool _kinematic; |
90 | private float _buoyancy; | 76 | private float _buoyancy; |
91 | 77 | ||
92 | // Membership in a linkset is controlled by this class. | ||
93 | private BSLinkset _linkset; | ||
94 | public BSLinkset Linkset | ||
95 | { | ||
96 | get { return _linkset; } | ||
97 | set { _linkset = value; } | ||
98 | } | ||
99 | |||
100 | private int _subscribedEventsMs = 0; | ||
101 | private int _nextCollisionOkTime = 0; | ||
102 | long _collidingStep; | ||
103 | long _collidingGroundStep; | ||
104 | |||
105 | private BulletBody m_body; | ||
106 | public BulletBody Body { | ||
107 | get { return m_body; } | ||
108 | set { m_body = value; } | ||
109 | } | ||
110 | |||
111 | private BSDynamics _vehicle; | 78 | private BSDynamics _vehicle; |
112 | 79 | ||
113 | private OMV.Vector3 _PIDTarget; | 80 | private OMV.Vector3 _PIDTarget; |
@@ -120,110 +87,116 @@ public sealed class BSPrim : PhysicsActor | |||
120 | 87 | ||
121 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | 88 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, |
122 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | 89 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) |
90 | : base(parent_scene, localID, primName, "BSPrim") | ||
123 | { | 91 | { |
124 | // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); | 92 | // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); |
125 | _localID = localID; | 93 | _physicsActorType = (int)ActorTypes.Prim; |
126 | _avName = primName; | ||
127 | _scene = parent_scene; | ||
128 | _position = pos; | 94 | _position = pos; |
129 | _size = size; | 95 | _size = size; |
130 | _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type | 96 | Scale = size; // the scale will be set by CreateGeom depending on object type |
131 | _orientation = rotation; | 97 | _orientation = rotation; |
132 | _buoyancy = 1f; | 98 | _buoyancy = 1f; |
133 | _velocity = OMV.Vector3.Zero; | 99 | _velocity = OMV.Vector3.Zero; |
134 | _rotationalVelocity = OMV.Vector3.Zero; | 100 | _rotationalVelocity = OMV.Vector3.Zero; |
135 | _hullKey = 0; | 101 | BaseShape = pbs; |
136 | _meshKey = 0; | ||
137 | _pbs = pbs; | ||
138 | _isPhysical = pisPhysical; | 102 | _isPhysical = pisPhysical; |
139 | _isVolumeDetect = false; | 103 | _isVolumeDetect = false; |
140 | _subscribedEventsMs = 0; | 104 | _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material |
141 | _friction = _scene.Params.defaultFriction; // TODO: compute based on object material | 105 | _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material |
142 | _density = _scene.Params.defaultDensity; // TODO: compute based on object material | 106 | _restitution = PhysicsScene.Params.defaultRestitution; |
143 | _restitution = _scene.Params.defaultRestitution; | 107 | _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness |
144 | _linkset = new BSLinkset(_scene, this); // a linkset of one | ||
145 | _vehicle = new BSDynamics(this); // add vehicleness | ||
146 | _mass = CalculateMass(); | 108 | _mass = CalculateMass(); |
147 | // do the actual object creation at taint time | 109 | |
110 | // No body or shape yet | ||
111 | PhysBody = new BulletBody(LocalID, IntPtr.Zero); | ||
112 | PhysShape = new BulletShape(IntPtr.Zero); | ||
113 | |||
148 | DetailLog("{0},BSPrim.constructor,call", LocalID); | 114 | DetailLog("{0},BSPrim.constructor,call", LocalID); |
149 | _scene.TaintedObject("BSPrim.create", delegate() | 115 | // do the actual object creation at taint time |
116 | PhysicsScene.TaintedObject("BSPrim.create", delegate() | ||
150 | { | 117 | { |
151 | RecreateGeomAndObject(); | 118 | CreateGeomAndObject(true); |
152 | 119 | ||
153 | // Get the pointer to the physical body for this object. | 120 | CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr); |
154 | // At the moment, we're still letting BulletSim manage the creation and destruction | ||
155 | // of the object. Someday we'll move that into the C# code. | ||
156 | m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID)); | ||
157 | }); | 121 | }); |
158 | } | 122 | } |
159 | 123 | ||
160 | // called when this prim is being destroyed and we should free all the resources | 124 | // called when this prim is being destroyed and we should free all the resources |
161 | public void Destroy() | 125 | public override void Destroy() |
162 | { | 126 | { |
163 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); | 127 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); |
164 | 128 | ||
165 | // Undo any links between me and any other object | 129 | // Undo any links between me and any other object |
166 | BSPrim parentBefore = _linkset.LinksetRoot; | 130 | BSPhysObject parentBefore = Linkset.LinksetRoot; |
167 | int childrenBefore = _linkset.NumberOfChildren; | 131 | int childrenBefore = Linkset.NumberOfChildren; |
168 | 132 | ||
169 | _linkset = _linkset.RemoveMeFromLinkset(this); | 133 | Linkset = Linkset.RemoveMeFromLinkset(this); |
170 | 134 | ||
171 | DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}", | 135 | DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}", |
172 | LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); | 136 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); |
173 | 137 | ||
174 | // Undo any vehicle properties | 138 | // Undo any vehicle properties |
175 | this.VehicleType = (int)Vehicle.TYPE_NONE; | 139 | this.VehicleType = (int)Vehicle.TYPE_NONE; |
176 | 140 | ||
177 | _scene.TaintedObject("BSPrim.destroy", delegate() | 141 | PhysicsScene.TaintedObject("BSPrim.destroy", delegate() |
178 | { | 142 | { |
179 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); | 143 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); |
180 | // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. | 144 | // If there are physical body and shape, release my use of same. |
181 | BulletSimAPI.DestroyObject(_scene.WorldID, LocalID); | 145 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); |
146 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | ||
182 | }); | 147 | }); |
183 | } | 148 | } |
184 | 149 | ||
185 | public override bool Stopped { | 150 | // No one uses this property. |
186 | get { return _stopped; } | 151 | public override bool Stopped { |
152 | get { return false; } | ||
187 | } | 153 | } |
188 | public override OMV.Vector3 Size { | 154 | public override OMV.Vector3 Size { |
189 | get { return _size; } | 155 | get { return _size; } |
190 | set { | 156 | set { |
157 | // 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. | ||
191 | _size = value; | 159 | _size = value; |
192 | _scene.TaintedObject("BSPrim.setSize", delegate() | 160 | ForceBodyShapeRebuild(false); |
193 | { | 161 | } |
194 | _mass = CalculateMass(); // changing size changes the mass | ||
195 | BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical); | ||
196 | // DetailLog("{0}: BSPrim.setSize: size={1}, mass={2}, physical={3}", LocalID, _size, _mass, IsPhysical); | ||
197 | RecreateGeomAndObject(); | ||
198 | }); | ||
199 | } | ||
200 | } | 162 | } |
201 | public override PrimitiveBaseShape Shape { | 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 | |||
167 | public override PrimitiveBaseShape Shape { | ||
202 | set { | 168 | set { |
203 | _pbs = value; | 169 | BaseShape = value; |
204 | _scene.TaintedObject("BSPrim.setShape", delegate() | 170 | ForceBodyShapeRebuild(false); |
205 | { | 171 | } |
206 | _mass = CalculateMass(); // changing the shape changes the mass | ||
207 | RecreateGeomAndObject(); | ||
208 | }); | ||
209 | } | ||
210 | } | 172 | } |
211 | public override uint LocalID { | 173 | // Whatever the linkset wants is what I want. |
212 | set { _localID = value; } | 174 | public override BSPhysicsShapeType PreferredPhysicalShape |
213 | get { return _localID; } | 175 | { get { return Linkset.PreferredPhysicalShape(this); } } |
176 | |||
177 | public override bool ForceBodyShapeRebuild(bool inTaintTime) | ||
178 | { | ||
179 | LastAssetBuildFailed = false; | ||
180 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() | ||
181 | { | ||
182 | _mass = CalculateMass(); // changing the shape changes the mass | ||
183 | CreateGeomAndObject(true); | ||
184 | }); | ||
185 | return true; | ||
214 | } | 186 | } |
215 | public override bool Grabbed { | 187 | public override bool Grabbed { |
216 | set { _grabbed = value; | 188 | set { _grabbed = value; |
217 | } | 189 | } |
218 | } | 190 | } |
219 | public override bool Selected { | 191 | public override bool Selected { |
220 | set { | 192 | set { |
221 | _isSelected = value; | 193 | _isSelected = value; |
222 | _scene.TaintedObject("BSPrim.setSelected", delegate() | 194 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() |
223 | { | 195 | { |
224 | SetObjectDynamic(); | 196 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); |
197 | SetObjectDynamic(false); | ||
225 | }); | 198 | }); |
226 | } | 199 | } |
227 | } | 200 | } |
228 | public override void CrossingFailure() { return; } | 201 | public override void CrossingFailure() { return; } |
229 | 202 | ||
@@ -232,158 +205,260 @@ public sealed class BSPrim : PhysicsActor | |||
232 | BSPrim parent = obj as BSPrim; | 205 | BSPrim parent = obj as BSPrim; |
233 | if (parent != null) | 206 | if (parent != null) |
234 | { | 207 | { |
235 | DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, parent.LocalID); | 208 | BSPhysObject parentBefore = Linkset.LinksetRoot; |
236 | BSPrim parentBefore = _linkset.LinksetRoot; | 209 | int childrenBefore = Linkset.NumberOfChildren; |
237 | int childrenBefore = _linkset.NumberOfChildren; | ||
238 | 210 | ||
239 | _linkset = parent.Linkset.AddMeToLinkset(this); | 211 | Linkset = parent.Linkset.AddMeToLinkset(this); |
240 | 212 | ||
241 | DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", | 213 | DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", |
242 | LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); | 214 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); |
243 | } | 215 | } |
244 | return; | 216 | return; |
245 | } | 217 | } |
246 | 218 | ||
247 | // delink me from my linkset | 219 | // delink me from my linkset |
248 | public override void delink() { | 220 | public override void delink() { |
249 | // TODO: decide if this parent checking needs to happen at taint time | 221 | // TODO: decide if this parent checking needs to happen at taint time |
250 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen | 222 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen |
251 | DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID, | ||
252 | _linkset.LinksetRoot._avName+"/"+_linkset.LinksetRoot.LocalID.ToString()); | ||
253 | 223 | ||
254 | BSPrim parentBefore = _linkset.LinksetRoot; | 224 | BSPhysObject parentBefore = Linkset.LinksetRoot; |
255 | int childrenBefore = _linkset.NumberOfChildren; | 225 | int childrenBefore = Linkset.NumberOfChildren; |
256 | 226 | ||
257 | _linkset = _linkset.RemoveMeFromLinkset(this); | 227 | Linkset = Linkset.RemoveMeFromLinkset(this); |
258 | 228 | ||
259 | DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", | 229 | DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", |
260 | LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); | 230 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); |
261 | return; | 231 | return; |
262 | } | 232 | } |
263 | 233 | ||
264 | // Set motion values to zero. | 234 | // Set motion values to zero. |
265 | // Do it to the properties so the values get set in the physics engine. | 235 | // Do it to the properties so the values get set in the physics engine. |
266 | // Push the setting of the values to the viewer. | 236 | // Push the setting of the values to the viewer. |
267 | // Called at taint time! | 237 | // Called at taint time! |
268 | public void ZeroMotion() | 238 | public override void ZeroMotion(bool inTaintTime) |
269 | { | 239 | { |
270 | _velocity = OMV.Vector3.Zero; | 240 | _velocity = OMV.Vector3.Zero; |
271 | _acceleration = OMV.Vector3.Zero; | 241 | _acceleration = OMV.Vector3.Zero; |
272 | _rotationalVelocity = OMV.Vector3.Zero; | 242 | _rotationalVelocity = OMV.Vector3.Zero; |
273 | 243 | ||
274 | // Zero some other properties directly into the physics engine | 244 | // Zero some other properties in the physics engine |
275 | BulletSimAPI.SetVelocity2(Body.Ptr, OMV.Vector3.Zero); | 245 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
276 | BulletSimAPI.SetAngularVelocity2(Body.Ptr, OMV.Vector3.Zero); | 246 | { |
277 | BulletSimAPI.SetInterpolation2(Body.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero); | 247 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); |
278 | BulletSimAPI.ClearForces2(Body.Ptr); | 248 | }); |
249 | } | ||
250 | public override void ZeroAngularMotion(bool inTaintTime) | ||
251 | { | ||
252 | _rotationalVelocity = OMV.Vector3.Zero; | ||
253 | // Zero some other properties in the physics engine | ||
254 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | ||
255 | { | ||
256 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | ||
257 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | ||
258 | }); | ||
279 | } | 259 | } |
280 | 260 | ||
281 | public override void LockAngularMotion(OMV.Vector3 axis) | 261 | public override void LockAngularMotion(OMV.Vector3 axis) |
282 | { | 262 | { |
283 | // DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); | 263 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); |
284 | return; | 264 | return; |
285 | } | 265 | } |
286 | 266 | ||
287 | public override OMV.Vector3 Position { | 267 | public override OMV.Vector3 RawPosition |
288 | get { | 268 | { |
289 | if (!_linkset.IsRoot(this)) | 269 | get { return _position; } |
290 | // child prims move around based on their parent. Need to get the latest location | 270 | set { _position = value; } |
291 | _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | 271 | } |
272 | public override OMV.Vector3 Position { | ||
273 | get { | ||
274 | // child prims move around based on their parent. Need to get the latest location | ||
275 | if (!Linkset.IsRoot(this)) | ||
276 | _position = Linkset.Position(this); | ||
292 | 277 | ||
293 | // don't do the GetObjectPosition for root elements because this function is called a zillion times | 278 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. |
294 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | 279 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); |
295 | return _position; | 280 | return _position; |
296 | } | 281 | } |
297 | set { | 282 | set { |
283 | // If the position must be forced into the physics engine, use ForcePosition. | ||
284 | if (_position == value) | ||
285 | { | ||
286 | return; | ||
287 | } | ||
298 | _position = value; | 288 | _position = value; |
299 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? | 289 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? |
300 | _scene.TaintedObject("BSPrim.setPosition", delegate() | 290 | PositionSanityCheck(false); |
291 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() | ||
301 | { | 292 | { |
302 | // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 293 | // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
303 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); | 294 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
295 | ActivateIfPhysical(false); | ||
304 | }); | 296 | }); |
305 | } | 297 | } |
298 | } | ||
299 | public override OMV.Vector3 ForcePosition { | ||
300 | get { | ||
301 | _position = BulletSimAPI.GetPosition2(PhysBody.ptr); | ||
302 | return _position; | ||
303 | } | ||
304 | set { | ||
305 | _position = value; | ||
306 | // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better. | ||
307 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
308 | ActivateIfPhysical(false); | ||
309 | } | ||
310 | } | ||
311 | |||
312 | // Check that the current position is sane and, if not, modify the position to make it so. | ||
313 | // Check for being below terrain and being out of bounds. | ||
314 | // Returns 'true' of the position was made sane by some action. | ||
315 | private bool PositionSanityCheck(bool inTaintTime) | ||
316 | { | ||
317 | bool ret = false; | ||
318 | |||
319 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | ||
320 | OMV.Vector3 upForce = OMV.Vector3.Zero; | ||
321 | if (Position.Z < terrainHeight) | ||
322 | { | ||
323 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | ||
324 | float targetHeight = terrainHeight + (Size.Z / 2f); | ||
325 | // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. | ||
326 | upForce.Z = (terrainHeight - Position.Z) * 1f; | ||
327 | ret = true; | ||
328 | } | ||
329 | |||
330 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | ||
331 | { | ||
332 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | ||
333 | // TODO: a floating motor so object will bob in the water | ||
334 | if (Math.Abs(Position.Z - waterHeight) > 0.1f) | ||
335 | { | ||
336 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. | ||
337 | upForce.Z = (waterHeight - Position.Z) * 1f; | ||
338 | ret = true; | ||
339 | } | ||
340 | } | ||
341 | |||
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. | ||
345 | if (ret) | ||
346 | { | ||
347 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() | ||
348 | { | ||
349 | // Apply upforce and overcome gravity. | ||
350 | ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity; | ||
351 | }); | ||
352 | } | ||
353 | return ret; | ||
306 | } | 354 | } |
307 | 355 | ||
308 | // Return the effective mass of the object. | 356 | // Return the effective mass of the object. |
309 | // If there are multiple items in the linkset, add them together for the root | 357 | // If there are multiple items in the linkset, add them together for the root |
310 | public override float Mass | 358 | public override float Mass |
311 | { | 359 | { |
312 | get | 360 | get |
313 | { | 361 | { |
314 | return _linkset.LinksetMass; | 362 | return Linkset.LinksetMass; |
363 | // return _mass; | ||
315 | } | 364 | } |
316 | } | 365 | } |
317 | 366 | ||
318 | // used when we only want this prim's mass and not the linkset thing | 367 | // used when we only want this prim's mass and not the linkset thing |
319 | public float MassRaw { get { return _mass; } } | 368 | public override float RawMass { |
369 | get { return _mass; } | ||
370 | } | ||
371 | // Set the physical mass to the passed mass. | ||
372 | // Note that this does not change _mass! | ||
373 | public override void UpdatePhysicalMassProperties(float physMass) | ||
374 | { | ||
375 | if (IsStatic) | ||
376 | { | ||
377 | Inertia = OMV.Vector3.Zero; | ||
378 | BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia); | ||
379 | BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); | ||
380 | } | ||
381 | else | ||
382 | { | ||
383 | Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); | ||
384 | BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia); | ||
385 | BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); | ||
386 | // center of mass is at the zero of the object | ||
387 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation); | ||
388 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, Inertia); | ||
389 | } | ||
390 | } | ||
320 | 391 | ||
321 | // Is this used? | 392 | // Is this used? |
322 | public override OMV.Vector3 CenterOfMass | 393 | public override OMV.Vector3 CenterOfMass |
323 | { | 394 | { |
324 | get { return _linkset.CenterOfMass; } | 395 | get { return Linkset.CenterOfMass; } |
325 | } | 396 | } |
326 | 397 | ||
327 | // Is this used? | 398 | // Is this used? |
328 | public override OMV.Vector3 GeometricCenter | 399 | public override OMV.Vector3 GeometricCenter |
329 | { | 400 | { |
330 | get { return _linkset.GeometricCenter; } | 401 | get { return Linkset.GeometricCenter; } |
331 | } | 402 | } |
332 | 403 | ||
333 | public override OMV.Vector3 Force { | 404 | public override OMV.Vector3 Force { |
334 | get { return _force; } | 405 | get { return _force; } |
335 | set { | 406 | set { |
336 | _force = value; | 407 | _force = value; |
337 | _scene.TaintedObject("BSPrim.setForce", delegate() | 408 | PhysicsScene.TaintedObject("BSPrim.setForce", delegate() |
338 | { | 409 | { |
339 | // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); | 410 | // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); |
340 | // BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); | 411 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); |
341 | BulletSimAPI.SetObjectForce2(Body.Ptr, _force); | ||
342 | }); | 412 | }); |
343 | } | 413 | } |
344 | } | 414 | } |
345 | 415 | ||
346 | public override int VehicleType { | 416 | public override int VehicleType { |
347 | get { | 417 | get { |
348 | return (int)_vehicle.Type; // if we are a vehicle, return that type | 418 | return (int)_vehicle.Type; // if we are a vehicle, return that type |
349 | } | 419 | } |
350 | set { | 420 | set { |
351 | Vehicle type = (Vehicle)value; | 421 | Vehicle type = (Vehicle)value; |
352 | BSPrim vehiclePrim = this; | 422 | |
353 | _scene.TaintedObject("setVehicleType", delegate() | 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() | ||
354 | { | 427 | { |
355 | // Done at taint time so we're sure the physics engine is not using the variables | 428 | // Done at taint time so we're sure the physics engine is not using the variables |
356 | // Vehicle code changes the parameters for this vehicle type. | 429 | // Vehicle code changes the parameters for this vehicle type. |
357 | _vehicle.ProcessTypeChange(type); | 430 | _vehicle.ProcessTypeChange(type); |
358 | // Tell the scene about the vehicle so it will get processing each frame. | 431 | ActivateIfPhysical(false); |
359 | _scene.VehicleInSceneTypeChanged(this, type); | ||
360 | }); | 432 | }); |
361 | } | 433 | } |
362 | } | 434 | } |
363 | public override void VehicleFloatParam(int param, float value) | 435 | public override void VehicleFloatParam(int param, float value) |
364 | { | 436 | { |
365 | _scene.TaintedObject("BSPrim.VehicleFloatParam", delegate() | 437 | PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() |
366 | { | 438 | { |
367 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); | 439 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); |
440 | ActivateIfPhysical(false); | ||
368 | }); | 441 | }); |
369 | } | 442 | } |
370 | public override void VehicleVectorParam(int param, OMV.Vector3 value) | 443 | public override void VehicleVectorParam(int param, OMV.Vector3 value) |
371 | { | 444 | { |
372 | _scene.TaintedObject("BSPrim.VehicleVectorParam", delegate() | 445 | PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() |
373 | { | 446 | { |
374 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); | 447 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); |
448 | ActivateIfPhysical(false); | ||
375 | }); | 449 | }); |
376 | } | 450 | } |
377 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) | 451 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) |
378 | { | 452 | { |
379 | _scene.TaintedObject("BSPrim.VehicleRotationParam", delegate() | 453 | PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() |
380 | { | 454 | { |
381 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); | 455 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); |
456 | ActivateIfPhysical(false); | ||
382 | }); | 457 | }); |
383 | } | 458 | } |
384 | public override void VehicleFlags(int param, bool remove) | 459 | public override void VehicleFlags(int param, bool remove) |
385 | { | 460 | { |
386 | _scene.TaintedObject("BSPrim.VehicleFlags", delegate() | 461 | PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() |
387 | { | 462 | { |
388 | _vehicle.ProcessVehicleFlags(param, remove); | 463 | _vehicle.ProcessVehicleFlags(param, remove); |
389 | }); | 464 | }); |
@@ -391,143 +466,356 @@ public sealed class BSPrim : PhysicsActor | |||
391 | 466 | ||
392 | // Called each simulation step to advance vehicle characteristics. | 467 | // Called each simulation step to advance vehicle characteristics. |
393 | // Called from Scene when doing simulation step so we're in taint processing time. | 468 | // Called from Scene when doing simulation step so we're in taint processing time. |
394 | public void StepVehicle(float timeStep) | 469 | public override void StepVehicle(float timeStep) |
395 | { | 470 | { |
396 | if (IsPhysical) | 471 | if (IsPhysical && _vehicle.IsActive) |
472 | { | ||
397 | _vehicle.Step(timeStep); | 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 | } | ||
398 | } | 482 | } |
399 | 483 | ||
400 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | 484 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more |
401 | public override void SetVolumeDetect(int param) { | 485 | public override void SetVolumeDetect(int param) { |
402 | bool newValue = (param != 0); | 486 | bool newValue = (param != 0); |
403 | _isVolumeDetect = newValue; | 487 | if (_isVolumeDetect != newValue) |
404 | _scene.TaintedObject("BSPrim.SetVolumeDetect", delegate() | ||
405 | { | 488 | { |
406 | SetObjectDynamic(); | 489 | _isVolumeDetect = newValue; |
407 | }); | 490 | PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() |
408 | return; | 491 | { |
492 | // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); | ||
493 | SetObjectDynamic(true); | ||
494 | }); | ||
495 | } | ||
496 | return; | ||
409 | } | 497 | } |
410 | 498 | public override OMV.Vector3 Velocity { | |
411 | public override OMV.Vector3 Velocity { | 499 | get { return _velocity; } |
412 | get { return _velocity; } | ||
413 | set { | 500 | set { |
414 | _velocity = value; | 501 | _velocity = value; |
415 | _scene.TaintedObject("BSPrim.setVelocity", delegate() | 502 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() |
416 | { | 503 | { |
417 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); | 504 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); |
418 | BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); | 505 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); |
419 | }); | 506 | }); |
420 | } | 507 | } |
508 | } | ||
509 | public override OMV.Vector3 ForceVelocity { | ||
510 | get { return _velocity; } | ||
511 | set { | ||
512 | _velocity = value; | ||
513 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | ||
514 | } | ||
421 | } | 515 | } |
422 | public override OMV.Vector3 Torque { | 516 | public override OMV.Vector3 Torque { |
423 | get { return _torque; } | 517 | get { return _torque; } |
424 | set { _torque = value; | 518 | set { |
519 | _torque = value; | ||
520 | AddAngularForce(_torque, false, false); | ||
425 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); | 521 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); |
426 | } | 522 | } |
427 | } | 523 | } |
428 | public override float CollisionScore { | 524 | public override float CollisionScore { |
429 | get { return _collisionScore; } | 525 | get { return _collisionScore; } |
430 | set { _collisionScore = value; | 526 | set { _collisionScore = value; |
431 | } | 527 | } |
432 | } | 528 | } |
433 | public override OMV.Vector3 Acceleration { | 529 | public override OMV.Vector3 Acceleration { |
434 | get { return _acceleration; } | 530 | get { return _acceleration; } |
435 | set { _acceleration = value; } | 531 | set { _acceleration = value; } |
436 | } | 532 | } |
437 | public override OMV.Quaternion Orientation { | 533 | public override OMV.Quaternion RawOrientation |
534 | { | ||
535 | get { return _orientation; } | ||
536 | set { _orientation = value; } | ||
537 | } | ||
538 | public override OMV.Quaternion Orientation { | ||
438 | get { | 539 | get { |
439 | if (!_linkset.IsRoot(this)) | 540 | // Children move around because tied to parent. Get a fresh value. |
541 | if (!Linkset.IsRoot(this)) | ||
440 | { | 542 | { |
441 | // Children move around because tied to parent. Get a fresh value. | 543 | _orientation = Linkset.Orientation(this); |
442 | _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID); | ||
443 | } | 544 | } |
444 | return _orientation; | 545 | return _orientation; |
445 | } | 546 | } |
446 | set { | 547 | set { |
548 | if (_orientation == value) | ||
549 | return; | ||
447 | _orientation = value; | 550 | _orientation = value; |
448 | // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? | 551 | // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? |
449 | _scene.TaintedObject("BSPrim.setOrientation", delegate() | 552 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() |
450 | { | 553 | { |
451 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | 554 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); |
452 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 555 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
453 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); | 556 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
454 | }); | 557 | }); |
455 | } | 558 | } |
559 | } | ||
560 | // Go directly to Bullet to get/set the value. | ||
561 | public override OMV.Quaternion ForceOrientation | ||
562 | { | ||
563 | get | ||
564 | { | ||
565 | _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); | ||
566 | return _orientation; | ||
567 | } | ||
568 | set | ||
569 | { | ||
570 | _orientation = value; | ||
571 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
572 | } | ||
456 | } | 573 | } |
457 | public override int PhysicsActorType { | 574 | public override int PhysicsActorType { |
458 | get { return _physicsActorType; } | 575 | get { return _physicsActorType; } |
459 | set { _physicsActorType = value; | 576 | set { _physicsActorType = value; } |
460 | } | ||
461 | } | 577 | } |
462 | public override bool IsPhysical { | 578 | public override bool IsPhysical { |
463 | get { return _isPhysical; } | 579 | get { return _isPhysical; } |
464 | set { | 580 | set { |
465 | _isPhysical = value; | 581 | if (_isPhysical != value) |
466 | _scene.TaintedObject("BSPrim.setIsPhysical", delegate() | ||
467 | { | 582 | { |
468 | SetObjectDynamic(); | 583 | _isPhysical = value; |
469 | }); | 584 | PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() |
470 | } | 585 | { |
586 | // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); | ||
587 | SetObjectDynamic(true); | ||
588 | // whether phys-to-static or static-to-phys, the object is not moving. | ||
589 | ZeroMotion(true); | ||
590 | }); | ||
591 | } | ||
592 | } | ||
471 | } | 593 | } |
472 | 594 | ||
473 | // An object is static (does not move) if selected or not physical | 595 | // An object is static (does not move) if selected or not physical |
474 | private bool IsStatic | 596 | public override bool IsStatic |
475 | { | 597 | { |
476 | get { return _isSelected || !IsPhysical; } | 598 | get { return _isSelected || !IsPhysical; } |
477 | } | 599 | } |
478 | 600 | ||
479 | // An object is solid if it's not phantom and if it's not doing VolumeDetect | 601 | // An object is solid if it's not phantom and if it's not doing VolumeDetect |
480 | private bool IsSolid | 602 | public override bool IsSolid |
481 | { | 603 | { |
482 | get { return !IsPhantom && !_isVolumeDetect; } | 604 | get { return !IsPhantom && !_isVolumeDetect; } |
483 | } | 605 | } |
484 | 606 | ||
485 | // Make gravity work if the object is physical and not selected | 607 | // Make gravity work if the object is physical and not selected |
486 | // No locking here because only called when it is safe | 608 | // Called at taint-time!! |
487 | private void SetObjectDynamic() | 609 | private void SetObjectDynamic(bool forceRebuild) |
610 | { | ||
611 | // Recreate the physical object if necessary | ||
612 | CreateGeomAndObject(forceRebuild); | ||
613 | } | ||
614 | |||
615 | // Convert the simulator's physical properties into settings on BulletSim objects. | ||
616 | // There are four flags we're interested in: | ||
617 | // IsStatic: Object does not move, otherwise the object has mass and moves | ||
618 | // isSolid: other objects bounce off of this object | ||
619 | // isVolumeDetect: other objects pass through but can generate collisions | ||
620 | // collisionEvents: whether this object returns collision events | ||
621 | private void UpdatePhysicalParameters() | ||
488 | { | 622 | { |
489 | // RA: remove this for the moment. | 623 | // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape); |
490 | // The problem is that dynamic objects are hulls so if we are becoming physical | 624 | |
491 | // the shape has to be checked and possibly built. | 625 | // Mangling all the physical properties requires the object not be in the physical world. |
492 | // Maybe a VerifyCorrectPhysicalShape() routine? | 626 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). |
493 | // RecreateGeomAndObject(); | 627 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); |
628 | |||
629 | // Set up the object physicalness (does gravity and collisions move this object) | ||
630 | MakeDynamic(IsStatic); | ||
631 | |||
632 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) | ||
633 | _vehicle.Refresh(); | ||
494 | 634 | ||
495 | // Bullet wants static objects to have a mass of zero | 635 | // Arrange for collision events if the simulator wants them |
496 | float mass = IsStatic ? 0f : _mass; | 636 | EnableCollisions(SubscribedEvents()); |
497 | 637 | ||
498 | BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass); | 638 | // Make solid or not (do things bounce off or pass through this object). |
639 | MakeSolid(IsSolid); | ||
499 | 640 | ||
500 | // recompute any linkset parameters | 641 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); |
501 | _linkset.Refresh(this); | ||
502 | 642 | ||
503 | CollisionFlags cf = BulletSimAPI.GetCollisionFlags2(Body.Ptr); | 643 | // Rebuild its shape |
504 | // DetailLog("{0},BSPrim.SetObjectDynamic,taint,static={1},solid={2},mass={3}, cf={4}", LocalID, IsStatic, IsSolid, mass, cf); | 644 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); |
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 | |||
652 | // Recompute any linkset parameters. | ||
653 | // When going from non-physical to physical, this re-enables the constraints that | ||
654 | // had been automatically disabled when the mass was set to zero. | ||
655 | // For compound based linksets, this enables and disables interactions of the children. | ||
656 | Linkset.Refresh(this); | ||
657 | |||
658 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", | ||
659 | LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape); | ||
660 | } | ||
661 | |||
662 | // "Making dynamic" means changing to and from static. | ||
663 | // When static, gravity does not effect the object and it is fixed in space. | ||
664 | // When dynamic, the object can fall and be pushed by others. | ||
665 | // This is independent of its 'solidness' which controls what passes through | ||
666 | // this object and what interacts with it. | ||
667 | private void MakeDynamic(bool makeStatic) | ||
668 | { | ||
669 | if (makeStatic) | ||
670 | { | ||
671 | // Become a Bullet 'static' object type | ||
672 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
673 | // Stop all movement | ||
674 | ZeroMotion(true); | ||
675 | // Center of mass is at the center of the object | ||
676 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); | ||
677 | // Mass is zero which disables a bunch of physics stuff in Bullet | ||
678 | UpdatePhysicalMassProperties(0f); | ||
679 | // Set collision detection parameters | ||
680 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | ||
681 | { | ||
682 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | ||
683 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | ||
684 | } | ||
685 | // There can be special things needed for implementing linksets | ||
686 | Linkset.MakeStatic(this); | ||
687 | // The activation state is 'disabled' so Bullet will not try to act on it. | ||
688 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | ||
689 | // Start it out sleeping and physical actions could wake it up. | ||
690 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); | ||
691 | |||
692 | PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; | ||
693 | PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; | ||
694 | } | ||
695 | else | ||
696 | { | ||
697 | // Not a Bullet static object | ||
698 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||
699 | |||
700 | // Set various physical properties so internal dynamic properties will get computed correctly as they are set | ||
701 | BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); | ||
702 | BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); | ||
703 | |||
704 | // 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 | ||
706 | // BulletSimAPI.ClearAllForces2(BSBody.ptr); | ||
707 | |||
708 | // For good measure, make sure the transform is set through to the motion state | ||
709 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
710 | |||
711 | // Center of mass is at the center of the object | ||
712 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); | ||
713 | |||
714 | // A dynamic object has mass | ||
715 | UpdatePhysicalMassProperties(RawMass); | ||
716 | |||
717 | // Set collision detection parameters | ||
718 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | ||
719 | { | ||
720 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | ||
721 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | ||
722 | } | ||
723 | |||
724 | // Various values for simulation limits | ||
725 | BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); | ||
726 | BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime); | ||
727 | BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); | ||
728 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); | ||
729 | |||
730 | // There might be special things needed for implementing linksets. | ||
731 | Linkset.MakeDynamic(this); | ||
732 | |||
733 | // Force activation of the object so Bullet will act on it. | ||
734 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. | ||
735 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); | ||
736 | // BulletSimAPI.Activate2(BSBody.ptr, true); | ||
737 | |||
738 | PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; | ||
739 | PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; | ||
740 | } | ||
741 | } | ||
742 | |||
743 | // "Making solid" means that other object will not pass through this object. | ||
744 | // To make transparent, we create a Bullet ghost object. | ||
745 | // Note: This expects to be called from the UpdatePhysicalParameters() routine as | ||
746 | // the functions after this one set up the state of a possibly newly created collision body. | ||
747 | private void MakeSolid(bool makeSolid) | ||
748 | { | ||
749 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr); | ||
750 | if (makeSolid) | ||
751 | { | ||
752 | // Verify the previous code created the correct shape for this type of thing. | ||
753 | if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0) | ||
754 | { | ||
755 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); | ||
756 | } | ||
757 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
758 | } | ||
759 | else | ||
760 | { | ||
761 | if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0) | ||
762 | { | ||
763 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | ||
764 | } | ||
765 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
766 | PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; | ||
767 | PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; | ||
768 | } | ||
769 | } | ||
770 | |||
771 | // Enable physical actions. Bullet will keep sleeping non-moving physical objects so | ||
772 | // they need waking up when parameters are changed. | ||
773 | // Called in taint-time!! | ||
774 | private void ActivateIfPhysical(bool forceIt) | ||
775 | { | ||
776 | if (IsPhysical) | ||
777 | BulletSimAPI.Activate2(PhysBody.ptr, forceIt); | ||
778 | } | ||
779 | |||
780 | // Turn on or off the flag controlling whether collision events are returned to the simulator. | ||
781 | private void EnableCollisions(bool wantsCollisionEvents) | ||
782 | { | ||
783 | if (wantsCollisionEvents) | ||
784 | { | ||
785 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
786 | } | ||
787 | else | ||
788 | { | ||
789 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
790 | } | ||
505 | } | 791 | } |
506 | 792 | ||
507 | // prims don't fly | 793 | // prims don't fly |
508 | public override bool Flying { | 794 | public override bool Flying { |
509 | get { return _flying; } | 795 | get { return _flying; } |
510 | set { _flying = value; } | 796 | set { |
797 | _flying = value; | ||
798 | } | ||
511 | } | 799 | } |
512 | public override bool SetAlwaysRun { | 800 | public override bool SetAlwaysRun { |
513 | get { return _setAlwaysRun; } | 801 | get { return _setAlwaysRun; } |
514 | set { _setAlwaysRun = value; } | 802 | set { _setAlwaysRun = value; } |
515 | } | 803 | } |
516 | public override bool ThrottleUpdates { | 804 | public override bool ThrottleUpdates { |
517 | get { return _throttleUpdates; } | 805 | get { return _throttleUpdates; } |
518 | set { _throttleUpdates = value; } | 806 | set { _throttleUpdates = value; } |
519 | } | 807 | } |
520 | public override bool IsColliding { | 808 | public override bool IsColliding { |
521 | get { return (_collidingStep == _scene.SimulationStep); } | 809 | get { return (CollidingStep == PhysicsScene.SimulationStep); } |
522 | set { _isColliding = value; } | 810 | set { _isColliding = value; } |
523 | } | 811 | } |
524 | public override bool CollidingGround { | 812 | public override bool CollidingGround { |
525 | get { return (_collidingGroundStep == _scene.SimulationStep); } | 813 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } |
526 | set { _collidingGround = value; } | 814 | set { _collidingGround = value; } |
527 | } | 815 | } |
528 | public override bool CollidingObj { | 816 | public override bool CollidingObj { |
529 | get { return _collidingObj; } | 817 | get { return _collidingObj; } |
530 | set { _collidingObj = value; } | 818 | set { _collidingObj = value; } |
531 | } | 819 | } |
532 | public bool IsPhantom { | 820 | public bool IsPhantom { |
533 | get { | 821 | get { |
@@ -537,10 +825,19 @@ public sealed class BSPrim : PhysicsActor | |||
537 | return false; | 825 | return false; |
538 | } | 826 | } |
539 | } | 827 | } |
540 | public override bool FloatOnWater { | 828 | public override bool FloatOnWater { |
541 | set { _floatOnWater = value; } | 829 | set { |
830 | _floatOnWater = value; | ||
831 | PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() | ||
832 | { | ||
833 | if (_floatOnWater) | ||
834 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | ||
835 | else | ||
836 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | ||
837 | }); | ||
838 | } | ||
542 | } | 839 | } |
543 | public override OMV.Vector3 RotationalVelocity { | 840 | public override OMV.Vector3 RotationalVelocity { |
544 | get { | 841 | get { |
545 | /* | 842 | /* |
546 | OMV.Vector3 pv = OMV.Vector3.Zero; | 843 | OMV.Vector3 pv = OMV.Vector3.Zero; |
@@ -552,58 +849,76 @@ public sealed class BSPrim : PhysicsActor | |||
552 | */ | 849 | */ |
553 | 850 | ||
554 | return _rotationalVelocity; | 851 | return _rotationalVelocity; |
555 | } | 852 | } |
556 | set { | 853 | set { |
557 | _rotationalVelocity = value; | 854 | _rotationalVelocity = value; |
558 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); | 855 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); |
559 | _scene.TaintedObject("BSPrim.setRotationalVelocity", delegate() | 856 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() |
560 | { | 857 | { |
561 | // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | 858 | DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); |
562 | BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); | 859 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); |
563 | }); | 860 | }); |
564 | } | 861 | } |
565 | } | 862 | } |
566 | public override bool Kinematic { | 863 | public override OMV.Vector3 ForceRotationalVelocity { |
567 | get { return _kinematic; } | 864 | get { |
568 | set { _kinematic = value; | 865 | return _rotationalVelocity; |
866 | } | ||
867 | set { | ||
868 | _rotationalVelocity = value; | ||
869 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||
870 | } | ||
871 | } | ||
872 | public override bool Kinematic { | ||
873 | get { return _kinematic; } | ||
874 | set { _kinematic = value; | ||
569 | // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); | 875 | // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); |
570 | } | 876 | } |
571 | } | 877 | } |
572 | public override float Buoyancy { | 878 | public override float Buoyancy { |
573 | get { return _buoyancy; } | 879 | get { return _buoyancy; } |
574 | set { | 880 | set { |
575 | _buoyancy = value; | 881 | _buoyancy = value; |
576 | _scene.TaintedObject("BSPrim.setBuoyancy", delegate() | 882 | PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() |
577 | { | 883 | { |
578 | // DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 884 | ForceBuoyancy = _buoyancy; |
579 | BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); | ||
580 | }); | 885 | }); |
581 | } | 886 | } |
887 | } | ||
888 | public override float ForceBuoyancy { | ||
889 | get { return _buoyancy; } | ||
890 | set { | ||
891 | _buoyancy = value; | ||
892 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
893 | // Buoyancy is faked by changing the gravity applied to the object | ||
894 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | ||
895 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | ||
896 | } | ||
582 | } | 897 | } |
583 | 898 | ||
584 | // Used for MoveTo | 899 | // Used for MoveTo |
585 | public override OMV.Vector3 PIDTarget { | 900 | public override OMV.Vector3 PIDTarget { |
586 | set { _PIDTarget = value; } | 901 | set { _PIDTarget = value; } |
587 | } | 902 | } |
588 | public override bool PIDActive { | 903 | public override bool PIDActive { |
589 | set { _usePID = value; } | 904 | set { _usePID = value; } |
590 | } | 905 | } |
591 | public override float PIDTau { | 906 | public override float PIDTau { |
592 | set { _PIDTau = value; } | 907 | set { _PIDTau = value; } |
593 | } | 908 | } |
594 | 909 | ||
595 | // Used for llSetHoverHeight and maybe vehicle height | 910 | // Used for llSetHoverHeight and maybe vehicle height |
596 | // Hover Height will override MoveTo target's Z | 911 | // Hover Height will override MoveTo target's Z |
597 | public override bool PIDHoverActive { | 912 | public override bool PIDHoverActive { |
598 | set { _useHoverPID = value; } | 913 | set { _useHoverPID = value; } |
599 | } | 914 | } |
600 | public override float PIDHoverHeight { | 915 | public override float PIDHoverHeight { |
601 | set { _PIDHoverHeight = value; } | 916 | set { _PIDHoverHeight = value; } |
602 | } | 917 | } |
603 | public override PIDHoverType PIDHoverType { | 918 | public override PIDHoverType PIDHoverType { |
604 | set { _PIDHoverType = value; } | 919 | set { _PIDHoverType = value; } |
605 | } | 920 | } |
606 | public override float PIDHoverTau { | 921 | public override float PIDHoverTau { |
607 | set { _PIDHoverTao = value; } | 922 | set { _PIDHoverTao = value; } |
608 | } | 923 | } |
609 | 924 | ||
@@ -615,6 +930,10 @@ public sealed class BSPrim : PhysicsActor | |||
615 | 930 | ||
616 | private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); | 931 | private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); |
617 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 932 | public override void AddForce(OMV.Vector3 force, bool pushforce) { |
933 | AddForce(force, pushforce, false); | ||
934 | } | ||
935 | // Applying a force just adds this to the total force on the object. | ||
936 | public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | ||
618 | // for an object, doesn't matter if force is a pushforce or not | 937 | // for an object, doesn't matter if force is a pushforce or not |
619 | if (force.IsFinite()) | 938 | if (force.IsFinite()) |
620 | { | 939 | { |
@@ -624,56 +943,88 @@ public sealed class BSPrim : PhysicsActor | |||
624 | } | 943 | } |
625 | else | 944 | else |
626 | { | 945 | { |
627 | m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); | 946 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); |
628 | return; | 947 | return; |
629 | } | 948 | } |
630 | _scene.TaintedObject("BSPrim.AddForce", delegate() | 949 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() |
631 | { | 950 | { |
632 | OMV.Vector3 fSum = OMV.Vector3.Zero; | 951 | OMV.Vector3 fSum = OMV.Vector3.Zero; |
633 | lock (m_accumulatedForces) | 952 | lock (m_accumulatedForces) |
634 | { | 953 | { |
954 | // Sum the accumulated additional forces for one big force to apply once. | ||
635 | foreach (OMV.Vector3 v in m_accumulatedForces) | 955 | foreach (OMV.Vector3 v in m_accumulatedForces) |
636 | { | 956 | { |
637 | fSum += v; | 957 | fSum += v; |
638 | } | 958 | } |
639 | m_accumulatedForces.Clear(); | 959 | m_accumulatedForces.Clear(); |
640 | } | 960 | } |
641 | // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, _force); | 961 | DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); |
642 | BulletSimAPI.AddObjectForce2(Body.Ptr, fSum); | 962 | if (fSum != OMV.Vector3.Zero) |
963 | BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); | ||
643 | }); | 964 | }); |
644 | } | 965 | } |
645 | 966 | ||
646 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 967 | // An impulse force is scaled by the mass of the object. |
647 | // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); | 968 | public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime) |
648 | // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); | 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 | }); | ||
649 | } | 976 | } |
650 | public override void SetMomentum(OMV.Vector3 momentum) { | 977 | |
651 | // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); | 978 | private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>(); |
979 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | ||
980 | AddAngularForce(force, pushforce, false); | ||
652 | } | 981 | } |
653 | public override void SubscribeEvents(int ms) { | 982 | public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) |
654 | _subscribedEventsMs = ms; | 983 | { |
655 | if (ms > 0) | 984 | if (force.IsFinite()) |
656 | { | 985 | { |
657 | // make sure first collision happens | 986 | // _force += force; |
658 | _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs; | 987 | lock (m_accumulatedAngularForces) |
659 | 988 | m_accumulatedAngularForces.Add(new OMV.Vector3(force)); | |
660 | Scene.TaintedObject("BSPrim.SubscribeEvents", delegate() | ||
661 | { | ||
662 | BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
663 | }); | ||
664 | } | 989 | } |
665 | } | 990 | else |
666 | public override void UnSubscribeEvents() { | 991 | { |
667 | _subscribedEventsMs = 0; | 992 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); |
668 | Scene.TaintedObject("BSPrim.UnSubscribeEvents", delegate() | 993 | return; |
994 | } | ||
995 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() | ||
669 | { | 996 | { |
670 | BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 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 | } | ||
671 | }); | 1013 | }); |
672 | } | 1014 | } |
673 | public override bool SubscribedEvents() { | 1015 | // A torque impulse. |
674 | return (_subscribedEventsMs > 0); | 1016 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) |
1017 | { | ||
1018 | OMV.Vector3 applyImpulse = impulse; | ||
1019 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() | ||
1020 | { | ||
1021 | BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); | ||
1022 | }); | ||
675 | } | 1023 | } |
676 | 1024 | ||
1025 | public override void SetMomentum(OMV.Vector3 momentum) { | ||
1026 | // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); | ||
1027 | } | ||
677 | #region Mass Calculation | 1028 | #region Mass Calculation |
678 | 1029 | ||
679 | private float CalculateMass() | 1030 | private float CalculateMass() |
@@ -682,19 +1033,19 @@ public sealed class BSPrim : PhysicsActor | |||
682 | float tmp; | 1033 | float tmp; |
683 | 1034 | ||
684 | float returnMass = 0; | 1035 | float returnMass = 0; |
685 | float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; | 1036 | float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f; |
686 | float hollowVolume = hollowAmount * hollowAmount; | 1037 | float hollowVolume = hollowAmount * hollowAmount; |
687 | 1038 | ||
688 | switch (_pbs.ProfileShape) | 1039 | switch (BaseShape.ProfileShape) |
689 | { | 1040 | { |
690 | case ProfileShape.Square: | 1041 | case ProfileShape.Square: |
691 | // default box | 1042 | // default box |
692 | 1043 | ||
693 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | 1044 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) |
694 | { | 1045 | { |
695 | if (hollowAmount > 0.0) | 1046 | if (hollowAmount > 0.0) |
696 | { | 1047 | { |
697 | switch (_pbs.HollowShape) | 1048 | switch (BaseShape.HollowShape) |
698 | { | 1049 | { |
699 | case HollowShape.Square: | 1050 | case HollowShape.Square: |
700 | case HollowShape.Same: | 1051 | case HollowShape.Same: |
@@ -718,19 +1069,19 @@ public sealed class BSPrim : PhysicsActor | |||
718 | } | 1069 | } |
719 | } | 1070 | } |
720 | 1071 | ||
721 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | 1072 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) |
722 | { | 1073 | { |
723 | //a tube | 1074 | //a tube |
724 | 1075 | ||
725 | volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); | 1076 | volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX); |
726 | tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); | 1077 | tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY); |
727 | volume -= volume*tmp*tmp; | 1078 | volume -= volume*tmp*tmp; |
728 | 1079 | ||
729 | if (hollowAmount > 0.0) | 1080 | if (hollowAmount > 0.0) |
730 | { | 1081 | { |
731 | hollowVolume *= hollowAmount; | 1082 | hollowVolume *= hollowAmount; |
732 | 1083 | ||
733 | switch (_pbs.HollowShape) | 1084 | switch (BaseShape.HollowShape) |
734 | { | 1085 | { |
735 | case HollowShape.Square: | 1086 | case HollowShape.Square: |
736 | case HollowShape.Same: | 1087 | case HollowShape.Same: |
@@ -755,13 +1106,13 @@ public sealed class BSPrim : PhysicsActor | |||
755 | 1106 | ||
756 | case ProfileShape.Circle: | 1107 | case ProfileShape.Circle: |
757 | 1108 | ||
758 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | 1109 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) |
759 | { | 1110 | { |
760 | volume *= 0.78539816339f; // elipse base | 1111 | volume *= 0.78539816339f; // elipse base |
761 | 1112 | ||
762 | if (hollowAmount > 0.0) | 1113 | if (hollowAmount > 0.0) |
763 | { | 1114 | { |
764 | switch (_pbs.HollowShape) | 1115 | switch (BaseShape.HollowShape) |
765 | { | 1116 | { |
766 | case HollowShape.Same: | 1117 | case HollowShape.Same: |
767 | case HollowShape.Circle: | 1118 | case HollowShape.Circle: |
@@ -783,19 +1134,19 @@ public sealed class BSPrim : PhysicsActor | |||
783 | } | 1134 | } |
784 | } | 1135 | } |
785 | 1136 | ||
786 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | 1137 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) |
787 | { | 1138 | { |
788 | volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); | 1139 | volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX); |
789 | tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); | 1140 | tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); |
790 | volume *= (1.0f - tmp * tmp); | 1141 | volume *= (1.0f - tmp * tmp); |
791 | 1142 | ||
792 | if (hollowAmount > 0.0) | 1143 | if (hollowAmount > 0.0) |
793 | { | 1144 | { |
794 | 1145 | ||
795 | // calculate the hollow volume by it's shape compared to the prim shape | 1146 | // calculate the hollow volume by it's shape compared to the prim shape |
796 | hollowVolume *= hollowAmount; | 1147 | hollowVolume *= hollowAmount; |
797 | 1148 | ||
798 | switch (_pbs.HollowShape) | 1149 | switch (BaseShape.HollowShape) |
799 | { | 1150 | { |
800 | case HollowShape.Same: | 1151 | case HollowShape.Same: |
801 | case HollowShape.Circle: | 1152 | case HollowShape.Circle: |
@@ -819,7 +1170,7 @@ public sealed class BSPrim : PhysicsActor | |||
819 | break; | 1170 | break; |
820 | 1171 | ||
821 | case ProfileShape.HalfCircle: | 1172 | case ProfileShape.HalfCircle: |
822 | if (_pbs.PathCurve == (byte)Extrusion.Curve1) | 1173 | if (BaseShape.PathCurve == (byte)Extrusion.Curve1) |
823 | { | 1174 | { |
824 | volume *= 0.52359877559829887307710723054658f; | 1175 | volume *= 0.52359877559829887307710723054658f; |
825 | } | 1176 | } |
@@ -827,7 +1178,7 @@ public sealed class BSPrim : PhysicsActor | |||
827 | 1178 | ||
828 | case ProfileShape.EquilateralTriangle: | 1179 | case ProfileShape.EquilateralTriangle: |
829 | 1180 | ||
830 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | 1181 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) |
831 | { | 1182 | { |
832 | volume *= 0.32475953f; | 1183 | volume *= 0.32475953f; |
833 | 1184 | ||
@@ -835,7 +1186,7 @@ public sealed class BSPrim : PhysicsActor | |||
835 | { | 1186 | { |
836 | 1187 | ||
837 | // calculate the hollow volume by it's shape compared to the prim shape | 1188 | // calculate the hollow volume by it's shape compared to the prim shape |
838 | switch (_pbs.HollowShape) | 1189 | switch (BaseShape.HollowShape) |
839 | { | 1190 | { |
840 | case HollowShape.Same: | 1191 | case HollowShape.Same: |
841 | case HollowShape.Triangle: | 1192 | case HollowShape.Triangle: |
@@ -860,11 +1211,11 @@ public sealed class BSPrim : PhysicsActor | |||
860 | volume *= (1.0f - hollowVolume); | 1211 | volume *= (1.0f - hollowVolume); |
861 | } | 1212 | } |
862 | } | 1213 | } |
863 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | 1214 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) |
864 | { | 1215 | { |
865 | volume *= 0.32475953f; | 1216 | volume *= 0.32475953f; |
866 | volume *= 0.01f * (float)(200 - _pbs.PathScaleX); | 1217 | volume *= 0.01f * (float)(200 - BaseShape.PathScaleX); |
867 | tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); | 1218 | tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); |
868 | volume *= (1.0f - tmp * tmp); | 1219 | volume *= (1.0f - tmp * tmp); |
869 | 1220 | ||
870 | if (hollowAmount > 0.0) | 1221 | if (hollowAmount > 0.0) |
@@ -872,7 +1223,7 @@ public sealed class BSPrim : PhysicsActor | |||
872 | 1223 | ||
873 | hollowVolume *= hollowAmount; | 1224 | hollowVolume *= hollowAmount; |
874 | 1225 | ||
875 | switch (_pbs.HollowShape) | 1226 | switch (BaseShape.HollowShape) |
876 | { | 1227 | { |
877 | case HollowShape.Same: | 1228 | case HollowShape.Same: |
878 | case HollowShape.Triangle: | 1229 | case HollowShape.Triangle: |
@@ -912,26 +1263,26 @@ public sealed class BSPrim : PhysicsActor | |||
912 | float profileBegin; | 1263 | float profileBegin; |
913 | float profileEnd; | 1264 | float profileEnd; |
914 | 1265 | ||
915 | if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) | 1266 | if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible) |
916 | { | 1267 | { |
917 | taperX1 = _pbs.PathScaleX * 0.01f; | 1268 | taperX1 = BaseShape.PathScaleX * 0.01f; |
918 | if (taperX1 > 1.0f) | 1269 | if (taperX1 > 1.0f) |
919 | taperX1 = 2.0f - taperX1; | 1270 | taperX1 = 2.0f - taperX1; |
920 | taperX = 1.0f - taperX1; | 1271 | taperX = 1.0f - taperX1; |
921 | 1272 | ||
922 | taperY1 = _pbs.PathScaleY * 0.01f; | 1273 | taperY1 = BaseShape.PathScaleY * 0.01f; |
923 | if (taperY1 > 1.0f) | 1274 | if (taperY1 > 1.0f) |
924 | taperY1 = 2.0f - taperY1; | 1275 | taperY1 = 2.0f - taperY1; |
925 | taperY = 1.0f - taperY1; | 1276 | taperY = 1.0f - taperY1; |
926 | } | 1277 | } |
927 | else | 1278 | else |
928 | { | 1279 | { |
929 | taperX = _pbs.PathTaperX * 0.01f; | 1280 | taperX = BaseShape.PathTaperX * 0.01f; |
930 | if (taperX < 0.0f) | 1281 | if (taperX < 0.0f) |
931 | taperX = -taperX; | 1282 | taperX = -taperX; |
932 | taperX1 = 1.0f - taperX; | 1283 | taperX1 = 1.0f - taperX; |
933 | 1284 | ||
934 | taperY = _pbs.PathTaperY * 0.01f; | 1285 | taperY = BaseShape.PathTaperY * 0.01f; |
935 | if (taperY < 0.0f) | 1286 | if (taperY < 0.0f) |
936 | taperY = -taperY; | 1287 | taperY = -taperY; |
937 | taperY1 = 1.0f - taperY; | 1288 | taperY1 = 1.0f - taperY; |
@@ -941,20 +1292,18 @@ public sealed class BSPrim : PhysicsActor | |||
941 | 1292 | ||
942 | volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); | 1293 | volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); |
943 | 1294 | ||
944 | pathBegin = (float)_pbs.PathBegin * 2.0e-5f; | 1295 | pathBegin = (float)BaseShape.PathBegin * 2.0e-5f; |
945 | pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f; | 1296 | pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f; |
946 | volume *= (pathEnd - pathBegin); | 1297 | volume *= (pathEnd - pathBegin); |
947 | 1298 | ||
948 | // this is crude aproximation | 1299 | // this is crude aproximation |
949 | profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f; | 1300 | profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f; |
950 | profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f; | 1301 | profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; |
951 | volume *= (profileEnd - profileBegin); | 1302 | volume *= (profileEnd - profileBegin); |
952 | 1303 | ||
953 | returnMass = _density * volume; | 1304 | returnMass = _density * volume; |
954 | 1305 | ||
955 | /* | 1306 | /* Comment out code that computes the mass of the linkset. That is done in the Linkset class. |
956 | * This change means each object keeps its own mass and the Mass property | ||
957 | * will return the sum if we're part of a linkset. | ||
958 | if (IsRootOfLinkset) | 1307 | if (IsRootOfLinkset) |
959 | { | 1308 | { |
960 | foreach (BSPrim prim in _childrenPrims) | 1309 | foreach (BSPrim prim in _childrenPrims) |
@@ -967,296 +1316,49 @@ public sealed class BSPrim : PhysicsActor | |||
967 | if (returnMass <= 0) | 1316 | if (returnMass <= 0) |
968 | returnMass = 0.0001f; | 1317 | returnMass = 0.0001f; |
969 | 1318 | ||
970 | if (returnMass > _scene.MaximumObjectMass) | 1319 | if (returnMass > PhysicsScene.MaximumObjectMass) |
971 | returnMass = _scene.MaximumObjectMass; | 1320 | returnMass = PhysicsScene.MaximumObjectMass; |
972 | 1321 | ||
973 | return returnMass; | 1322 | return returnMass; |
974 | }// end CalculateMass | 1323 | }// end CalculateMass |
975 | #endregion Mass Calculation | 1324 | #endregion Mass Calculation |
976 | 1325 | ||
977 | // Create the geometry information in Bullet for later use | 1326 | // Rebuild the geometry and object. |
978 | // The objects needs a hull if it's physical otherwise a mesh is enough | 1327 | // This is called when the shape changes so we need to recreate the mesh/hull. |
979 | // No locking here because this is done when we know physics is not simulating | 1328 | // Called at taint-time!!! |
980 | // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used | 1329 | private void CreateGeomAndObject(bool forceRebuild) |
981 | // Returns 'true' if the geometry was rebuilt | ||
982 | private bool CreateGeom(bool forceRebuild) | ||
983 | { | ||
984 | // the mesher thought this was too simple to mesh. Use a native Bullet collision shape. | ||
985 | bool ret = false; | ||
986 | if (!_scene.NeedsMeshing(_pbs)) | ||
987 | { | ||
988 | if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) | ||
989 | { | ||
990 | // if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) | ||
991 | // { | ||
992 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); | ||
993 | if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE)) | ||
994 | { | ||
995 | // DetailLog("{0},BSPrim.CreateGeom,sphere (force={1}", LocalID, forceRebuild); | ||
996 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; | ||
997 | // Bullet native objects are scaled by the Bullet engine so pass the size in | ||
998 | _scale = _size; | ||
999 | // TODO: do we need to check for and destroy a mesh or hull that might have been left from before? | ||
1000 | ret = true; | ||
1001 | } | ||
1002 | // } | ||
1003 | } | ||
1004 | else | ||
1005 | { | ||
1006 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size); | ||
1007 | if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX)) | ||
1008 | { | ||
1009 | // DetailLog("{0},BSPrim.CreateGeom,box (force={1})", LocalID, forceRebuild); | ||
1010 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; | ||
1011 | _scale = _size; | ||
1012 | // TODO: do we need to check for and destroy a mesh or hull that might have been left from before? | ||
1013 | ret = true; | ||
1014 | } | ||
1015 | } | ||
1016 | } | ||
1017 | else | ||
1018 | { | ||
1019 | if (IsPhysical) | ||
1020 | { | ||
1021 | if (forceRebuild || _hullKey == 0) | ||
1022 | { | ||
1023 | // physical objects require a hull for interaction. | ||
1024 | // This will create the mesh if it doesn't already exist | ||
1025 | CreateGeomHull(); | ||
1026 | ret = true; | ||
1027 | } | ||
1028 | } | ||
1029 | else | ||
1030 | { | ||
1031 | if (forceRebuild || _meshKey == 0) | ||
1032 | { | ||
1033 | // Static (non-physical) objects only need a mesh for bumping into | ||
1034 | CreateGeomMesh(); | ||
1035 | ret = true; | ||
1036 | } | ||
1037 | } | ||
1038 | } | ||
1039 | return ret; | ||
1040 | } | ||
1041 | |||
1042 | // No locking here because this is done when we know physics is not simulating | ||
1043 | private void CreateGeomMesh() | ||
1044 | { | ||
1045 | float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD; | ||
1046 | ulong newMeshKey = (ulong)_pbs.GetMeshKey(_size, lod); | ||
1047 | // m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _meshKey, newMeshKey); | ||
1048 | |||
1049 | // if this new shape is the same as last time, don't recreate the mesh | ||
1050 | if (_meshKey == newMeshKey) return; | ||
1051 | |||
1052 | // DetailLog("{0},BSPrim.CreateGeomMesh,create,key={1}", LocalID, newMeshKey); | ||
1053 | // Since we're recreating new, get rid of any previously generated shape | ||
1054 | if (_meshKey != 0) | ||
1055 | { | ||
1056 | // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey); | ||
1057 | // DetailLog("{0},BSPrim.CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey); | ||
1058 | BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); | ||
1059 | _mesh = null; | ||
1060 | _meshKey = 0; | ||
1061 | } | ||
1062 | |||
1063 | _meshKey = newMeshKey; | ||
1064 | // always pass false for physicalness as this creates some sort of bounding box which we don't need | ||
1065 | _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, lod, false); | ||
1066 | |||
1067 | int[] indices = _mesh.getIndexListAsInt(); | ||
1068 | List<OMV.Vector3> vertices = _mesh.getVertexList(); | ||
1069 | |||
1070 | float[] verticesAsFloats = new float[vertices.Count * 3]; | ||
1071 | int vi = 0; | ||
1072 | foreach (OMV.Vector3 vv in vertices) | ||
1073 | { | ||
1074 | verticesAsFloats[vi++] = vv.X; | ||
1075 | verticesAsFloats[vi++] = vv.Y; | ||
1076 | verticesAsFloats[vi++] = vv.Z; | ||
1077 | } | ||
1078 | |||
1079 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | ||
1080 | // LogHeader, _localID, _meshKey, indices.Length, vertices.Count); | ||
1081 | BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices, | ||
1082 | vertices.Count, verticesAsFloats); | ||
1083 | |||
1084 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; | ||
1085 | // meshes are already scaled by the meshmerizer | ||
1086 | _scale = new OMV.Vector3(1f, 1f, 1f); | ||
1087 | // DetailLog("{0},BSPrim.CreateGeomMesh,done", LocalID); | ||
1088 | return; | ||
1089 | } | ||
1090 | |||
1091 | // No locking here because this is done when we know physics is not simulating | ||
1092 | private void CreateGeomHull() | ||
1093 | { | 1330 | { |
1094 | float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD; | 1331 | // If this prim is part of a linkset, we must remove and restore the physical |
1095 | ulong newHullKey = (ulong)_pbs.GetMeshKey(_size, lod); | 1332 | // links if the body is rebuilt. |
1096 | // m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _hullKey, newHullKey); | 1333 | bool needToRestoreLinkset = false; |
1097 | 1334 | bool needToRestoreVehicle = false; | |
1098 | // if the hull hasn't changed, don't rebuild it | 1335 | |
1099 | if (newHullKey == _hullKey) return; | 1336 | // Create the correct physical representation for this type of object. |
1100 | 1337 | // Updates PhysBody and PhysShape with the new information. | |
1101 | // DetailLog("{0},BSPrim.CreateGeomHull,create,oldKey={1},newKey={2}", LocalID, _hullKey, newHullKey); | 1338 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. |
1102 | 1339 | // Returns 'true' if either the body or the shape was changed. | |
1103 | // Since we're recreating new, get rid of any previously generated shape | 1340 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) |
1104 | if (_hullKey != 0) | ||
1105 | { | ||
1106 | // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); | ||
1107 | // DetailLog("{0},BSPrim.CreateGeomHull,deleteOldHull,key={1}", LocalID, _hullKey); | ||
1108 | BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); | ||
1109 | _hullKey = 0; | ||
1110 | } | ||
1111 | |||
1112 | _hullKey = newHullKey; | ||
1113 | |||
1114 | // Make sure the underlying mesh exists and is correct | ||
1115 | CreateGeomMesh(); | ||
1116 | |||
1117 | int[] indices = _mesh.getIndexListAsInt(); | ||
1118 | List<OMV.Vector3> vertices = _mesh.getVertexList(); | ||
1119 | |||
1120 | //format conversion from IMesh format to DecompDesc format | ||
1121 | List<int> convIndices = new List<int>(); | ||
1122 | List<float3> convVertices = new List<float3>(); | ||
1123 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
1124 | { | ||
1125 | convIndices.Add(indices[ii]); | ||
1126 | } | ||
1127 | foreach (OMV.Vector3 vv in vertices) | ||
1128 | { | 1341 | { |
1129 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | 1342 | // Called if the current prim body is about to be destroyed. |
1130 | } | 1343 | // Remove all the physical dependencies on the old body. |
1344 | // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) | ||
1345 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); | ||
1346 | needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); | ||
1347 | }); | ||
1131 | 1348 | ||
1132 | // setup and do convex hull conversion | 1349 | if (needToRestoreLinkset) |
1133 | _hulls = new List<ConvexResult>(); | ||
1134 | DecompDesc dcomp = new DecompDesc(); | ||
1135 | dcomp.mIndices = convIndices; | ||
1136 | dcomp.mVertices = convVertices; | ||
1137 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
1138 | // create the hull into the _hulls variable | ||
1139 | convexBuilder.process(dcomp); | ||
1140 | |||
1141 | // Convert the vertices and indices for passing to unmanaged. | ||
1142 | // The hull information is passed as a large floating point array. | ||
1143 | // The format is: | ||
1144 | // convHulls[0] = number of hulls | ||
1145 | // convHulls[1] = number of vertices in first hull | ||
1146 | // convHulls[2] = hull centroid X coordinate | ||
1147 | // convHulls[3] = hull centroid Y coordinate | ||
1148 | // convHulls[4] = hull centroid Z coordinate | ||
1149 | // convHulls[5] = first hull vertex X | ||
1150 | // convHulls[6] = first hull vertex Y | ||
1151 | // convHulls[7] = first hull vertex Z | ||
1152 | // convHulls[8] = second hull vertex X | ||
1153 | // ... | ||
1154 | // convHulls[n] = number of vertices in second hull | ||
1155 | // convHulls[n+1] = second hull centroid X coordinate | ||
1156 | // ... | ||
1157 | // | ||
1158 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
1159 | // data structures that do not need to be converted in order to pass to Bullet. | ||
1160 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
1161 | int hullCount = _hulls.Count; | ||
1162 | int totalVertices = 1; // include one for the count of the hulls | ||
1163 | foreach (ConvexResult cr in _hulls) | ||
1164 | { | 1350 | { |
1165 | totalVertices += 4; // add four for the vertex count and centroid | 1351 | // If physical body dependencies were removed, restore them |
1166 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | 1352 | Linkset.RestoreBodyDependencies(this); |
1167 | } | 1353 | } |
1168 | float[] convHulls = new float[totalVertices]; | 1354 | if (needToRestoreVehicle) |
1169 | |||
1170 | convHulls[0] = (float)hullCount; | ||
1171 | int jj = 1; | ||
1172 | foreach (ConvexResult cr in _hulls) | ||
1173 | { | 1355 | { |
1174 | // copy vertices for index access | 1356 | // If physical body dependencies were removed, restore them |
1175 | float3[] verts = new float3[cr.HullVertices.Count]; | 1357 | _vehicle.RestoreBodyDependencies(this); |
1176 | int kk = 0; | ||
1177 | foreach (float3 ff in cr.HullVertices) | ||
1178 | { | ||
1179 | verts[kk++] = ff; | ||
1180 | } | ||
1181 | |||
1182 | // add to the array one hull's worth of data | ||
1183 | convHulls[jj++] = cr.HullIndices.Count; | ||
1184 | convHulls[jj++] = 0f; // centroid x,y,z | ||
1185 | convHulls[jj++] = 0f; | ||
1186 | convHulls[jj++] = 0f; | ||
1187 | foreach (int ind in cr.HullIndices) | ||
1188 | { | ||
1189 | convHulls[jj++] = verts[ind].x; | ||
1190 | convHulls[jj++] = verts[ind].y; | ||
1191 | convHulls[jj++] = verts[ind].z; | ||
1192 | } | ||
1193 | } | 1358 | } |
1194 | 1359 | ||
1195 | // create the hull definition in Bullet | 1360 | // Make sure the properties are set on the new object |
1196 | // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount); | 1361 | UpdatePhysicalParameters(); |
1197 | BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls); | ||
1198 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; | ||
1199 | // meshes are already scaled by the meshmerizer | ||
1200 | _scale = new OMV.Vector3(1f, 1f, 1f); | ||
1201 | // DetailLog("{0},BSPrim.CreateGeomHull,done", LocalID); | ||
1202 | return; | ||
1203 | } | ||
1204 | |||
1205 | // Callback from convex hull creater with a newly created hull. | ||
1206 | // Just add it to the collection of hulls for this shape. | ||
1207 | private void HullReturn(ConvexResult result) | ||
1208 | { | ||
1209 | _hulls.Add(result); | ||
1210 | return; | ||
1211 | } | ||
1212 | |||
1213 | // Create an object in Bullet if it has not already been created | ||
1214 | // No locking here because this is done when the physics engine is not simulating | ||
1215 | // Returns 'true' if an object was actually created. | ||
1216 | private bool CreateObject() | ||
1217 | { | ||
1218 | // this routine is called when objects are rebuilt. | ||
1219 | |||
1220 | // the mesh or hull must have already been created in Bullet | ||
1221 | ShapeData shape; | ||
1222 | FillShapeInfo(out shape); | ||
1223 | // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type); | ||
1224 | bool ret = BulletSimAPI.CreateObject(_scene.WorldID, shape); | ||
1225 | |||
1226 | // the CreateObject() may have recreated the rigid body. Make sure we have the latest. | ||
1227 | Body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID)); | ||
1228 | |||
1229 | return ret; | ||
1230 | } | ||
1231 | |||
1232 | // Copy prim's info into the BulletSim shape description structure | ||
1233 | public void FillShapeInfo(out ShapeData shape) | ||
1234 | { | ||
1235 | shape.ID = _localID; | ||
1236 | shape.Type = _shapeType; | ||
1237 | shape.Position = _position; | ||
1238 | shape.Rotation = _orientation; | ||
1239 | shape.Velocity = _velocity; | ||
1240 | shape.Scale = _scale; | ||
1241 | shape.Mass = _isPhysical ? _mass : 0f; | ||
1242 | shape.Buoyancy = _buoyancy; | ||
1243 | shape.HullKey = _hullKey; | ||
1244 | shape.MeshKey = _meshKey; | ||
1245 | shape.Friction = _friction; | ||
1246 | shape.Restitution = _restitution; | ||
1247 | shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; | ||
1248 | shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; | ||
1249 | } | ||
1250 | |||
1251 | |||
1252 | // Rebuild the geometry and object. | ||
1253 | // This is called when the shape changes so we need to recreate the mesh/hull. | ||
1254 | // No locking here because this is done when the physics engine is not simulating | ||
1255 | private void RecreateGeomAndObject() | ||
1256 | { | ||
1257 | // m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID); | ||
1258 | if (CreateGeom(true)) | ||
1259 | CreateObject(); | ||
1260 | return; | 1362 | return; |
1261 | } | 1363 | } |
1262 | 1364 | ||
@@ -1277,7 +1379,7 @@ public sealed class BSPrim : PhysicsActor | |||
1277 | const float ACCELERATION_TOLERANCE = 0.01f; | 1379 | const float ACCELERATION_TOLERANCE = 0.01f; |
1278 | const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; | 1380 | const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; |
1279 | 1381 | ||
1280 | public void UpdateProperties(EntityProperties entprop) | 1382 | public override void UpdateProperties(EntityProperties entprop) |
1281 | { | 1383 | { |
1282 | /* | 1384 | /* |
1283 | UpdatedProperties changed = 0; | 1385 | UpdatedProperties changed = 0; |
@@ -1315,7 +1417,7 @@ public sealed class BSPrim : PhysicsActor | |||
1315 | if (changed != 0) | 1417 | if (changed != 0) |
1316 | { | 1418 | { |
1317 | // Only update the position of single objects and linkset roots | 1419 | // Only update the position of single objects and linkset roots |
1318 | if (this._parentPrim == null) | 1420 | if (Linkset.IsRoot(this)) |
1319 | { | 1421 | { |
1320 | base.RequestPhysicsterseUpdate(); | 1422 | base.RequestPhysicsterseUpdate(); |
1321 | } | 1423 | } |
@@ -1325,78 +1427,46 @@ public sealed class BSPrim : PhysicsActor | |||
1325 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. | 1427 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. |
1326 | 1428 | ||
1327 | // Updates only for individual prims and for the root object of a linkset. | 1429 | // Updates only for individual prims and for the root object of a linkset. |
1328 | if (_linkset.IsRoot(this)) | 1430 | if (Linkset.IsRoot(this)) |
1329 | { | 1431 | { |
1330 | // Assign to the local variables so the normal set action does not happen | 1432 | // Assign directly to the local variables so the normal set action does not happen |
1331 | _position = entprop.Position; | 1433 | _position = entprop.Position; |
1332 | _orientation = entprop.Rotation; | 1434 | _orientation = entprop.Rotation; |
1333 | _velocity = entprop.Velocity; | 1435 | _velocity = entprop.Velocity; |
1334 | _acceleration = entprop.Acceleration; | 1436 | _acceleration = entprop.Acceleration; |
1335 | _rotationalVelocity = entprop.RotationalVelocity; | 1437 | _rotationalVelocity = entprop.RotationalVelocity; |
1336 | 1438 | ||
1337 | // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}", | 1439 | // The sanity check can change the velocity and/or position. |
1338 | // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | 1440 | if (PositionSanityCheck(true)) |
1339 | // DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 1441 | { |
1340 | // LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | 1442 | entprop.Position = _position; |
1443 | entprop.Velocity = _velocity; | ||
1444 | } | ||
1445 | |||
1446 | // remember the current and last set values | ||
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}", | ||
1452 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); | ||
1453 | |||
1454 | // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG | ||
1341 | 1455 | ||
1342 | base.RequestPhysicsterseUpdate(); | 1456 | base.RequestPhysicsterseUpdate(); |
1343 | } | 1457 | } |
1344 | /* | 1458 | /* |
1345 | else | 1459 | else |
1346 | { | 1460 | { |
1347 | // For debugging, we also report the movement of children | 1461 | // For debugging, report the movement of children |
1348 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 1462 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", |
1349 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | 1463 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, |
1350 | entprop.Acceleration, entprop.RotationalVelocity); | 1464 | entprop.Acceleration, entprop.RotationalVelocity); |
1351 | } | 1465 | } |
1352 | */ | 1466 | */ |
1353 | } | ||
1354 | |||
1355 | // I've collided with something | ||
1356 | CollisionEventUpdate collisionCollection; | ||
1357 | public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | ||
1358 | { | ||
1359 | // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith); | ||
1360 | |||
1361 | // The following lines make IsColliding() and IsCollidingGround() work | ||
1362 | _collidingStep = _scene.SimulationStep; | ||
1363 | if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID) | ||
1364 | { | ||
1365 | _collidingGroundStep = _scene.SimulationStep; | ||
1366 | } | ||
1367 | |||
1368 | // DetailLog("{0},BSPrim.Collison,call,with={1}", LocalID, collidingWith); | ||
1369 | |||
1370 | // if someone is subscribed to collision events.... | ||
1371 | if (_subscribedEventsMs != 0) { | ||
1372 | // throttle the collisions to the number of milliseconds specified in the subscription | ||
1373 | int nowTime = _scene.SimulationNowTime; | ||
1374 | if (nowTime >= _nextCollisionOkTime) { | ||
1375 | _nextCollisionOkTime = nowTime + _subscribedEventsMs; | ||
1376 | 1467 | ||
1377 | if (collisionCollection == null) | 1468 | // The linkset implimentation might want to know about this. |
1378 | collisionCollection = new CollisionEventUpdate(); | 1469 | Linkset.UpdateProperties(this); |
1379 | collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | ||
1380 | } | ||
1381 | } | ||
1382 | } | ||
1383 | |||
1384 | // The scene is telling us it's time to pass our collected collisions into the simulator | ||
1385 | public void SendCollisions() | ||
1386 | { | ||
1387 | if (collisionCollection != null && collisionCollection.Count > 0) | ||
1388 | { | ||
1389 | base.SendCollisionUpdate(collisionCollection); | ||
1390 | // The collisionCollection structure is passed around in the simulator. | ||
1391 | // Make sure we don't have a handle to that one and that a new one is used next time. | ||
1392 | collisionCollection = null; | ||
1393 | } | ||
1394 | } | ||
1395 | |||
1396 | // Invoke the detailed logger and output something if it's enabled. | ||
1397 | private void DetailLog(string msg, params Object[] args) | ||
1398 | { | ||
1399 | Scene.PhysicsLogging.Write(msg, args); | ||
1400 | } | 1470 | } |
1401 | } | 1471 | } |
1402 | } | 1472 | } |