aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs396
1 files changed, 396 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs
new file mode 100644
index 0000000..23a0b8b
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs
@@ -0,0 +1,396 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32
33using OMV = OpenMetaverse;
34
35namespace OpenSim.Region.Physics.BulletSNPlugin
36{
37
38// When a child is linked, the relationship position of the child to the parent
39// is remembered so the child's world position can be recomputed when it is
40// removed from the linkset.
41sealed class BSLinksetCompoundInfo : BSLinksetInfo
42{
43 public OMV.Vector3 OffsetPos;
44 public OMV.Quaternion OffsetRot;
45 public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r)
46 {
47 OffsetPos = p;
48 OffsetRot = r;
49 }
50 public override void Clear()
51 {
52 OffsetPos = OMV.Vector3.Zero;
53 OffsetRot = OMV.Quaternion.Identity;
54 }
55 public override string ToString()
56 {
57 StringBuilder buff = new StringBuilder();
58 buff.Append("<p=");
59 buff.Append(OffsetPos.ToString());
60 buff.Append(",r=");
61 buff.Append(OffsetRot.ToString());
62 buff.Append(">");
63 return buff.ToString();
64 }
65};
66
67public sealed class BSLinksetCompound : BSLinkset
68{
69 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
70
71 public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
72 {
73 }
74
75 // For compound implimented linksets, if there are children, use compound shape for the root.
76 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
77 {
78 // Returning 'unknown' means we don't have a preference.
79 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
80 if (IsRoot(requestor) && HasAnyChildren)
81 {
82 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
83 }
84 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
85 return ret;
86 }
87
88 // When physical properties are changed the linkset needs to recalculate
89 // its internal properties.
90 public override void Refresh(BSPhysObject requestor)
91 {
92 // Something changed so do the rebuilding thing
93 // ScheduleRebuild();
94 }
95
96 // Schedule a refresh to happen after all the other taint processing.
97 private void ScheduleRebuild(BSPhysObject requestor)
98 {
99 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,rebuilding={1}",
100 requestor.LocalID, Rebuilding);
101 // When rebuilding, it is possible to set properties that would normally require a rebuild.
102 // If already rebuilding, don't request another rebuild.
103 if (!Rebuilding)
104 {
105 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", LinksetRoot.LocalID, delegate()
106 {
107 if (HasAnyChildren)
108 RecomputeLinksetCompound();
109 });
110 }
111 }
112
113 // The object is going dynamic (physical). Do any setup necessary
114 // for a dynamic linkset.
115 // Only the state of the passed object can be modified. The rest of the linkset
116 // has not yet been fully constructed.
117 // Return 'true' if any properties updated on the passed object.
118 // Called at taint-time!
119 public override bool MakeDynamic(BSPhysObject child)
120 {
121 bool ret = false;
122 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
123 if (IsRoot(child))
124 {
125 // The root is going dynamic. Make sure mass is properly set.
126 m_mass = ComputeLinksetMass();
127 ScheduleRebuild(LinksetRoot);
128 }
129 else
130 {
131 // The origional prims are removed from the world as the shape of the root compound
132 // shape takes over.
133 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
134 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
135 // We don't want collisions from the old linkset children.
136 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
137
138 child.PhysBody.collisionType = CollisionType.LinksetChild;
139
140 ret = true;
141 }
142 return ret;
143 }
144
145 // The object is going static (non-physical). Do any setup necessary for a static linkset.
146 // Return 'true' if any properties updated on the passed object.
147 // This doesn't normally happen -- OpenSim removes the objects from the physical
148 // world if it is a static linkset.
149 // Called at taint-time!
150 public override bool MakeStatic(BSPhysObject child)
151 {
152 bool ret = false;
153 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
154 if (IsRoot(child))
155 {
156 ScheduleRebuild(LinksetRoot);
157 }
158 else
159 {
160 // The non-physical children can come back to life.
161 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
162
163 child.PhysBody.collisionType = CollisionType.LinksetChild;
164
165 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
166 BulletSimAPI.Activate2(child.PhysBody.ptr, false);
167 ret = true;
168 }
169 return ret;
170 }
171
172 public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate)
173 {
174 // The user moving a child around requires the rebuilding of the linkset compound shape
175 // One problem is this happens when a border is crossed -- the simulator implementation
176 // is to store the position into the group which causes the move of the object
177 // but it also means all the child positions get updated.
178 // What would cause an unnecessary rebuild so we make sure the linkset is in a
179 // region before bothering to do a rebuild.
180 if (!IsRoot(updated)
181 && !physicalUpdate
182 && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
183 {
184 updated.LinksetInfo = null;
185 ScheduleRebuild(updated);
186 }
187 }
188
189 // Routine called when rebuilding the body of some member of the linkset.
190 // Since we don't keep in world relationships, do nothing unless it's a child changing.
191 // Returns 'true' of something was actually removed and would need restoring
192 // Called at taint-time!!
193 public override bool RemoveBodyDependencies(BSPrim child)
194 {
195 bool ret = false;
196
197 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
198 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(), IsRoot(child));
199
200 if (!IsRoot(child))
201 {
202 // Because it is a convenient time, recompute child world position and rotation based on
203 // its position in the linkset.
204 RecomputeChildWorldPosition(child, true);
205 }
206
207 // Cannot schedule a refresh/rebuild here because this routine is called when
208 // the linkset is being rebuilt.
209 // InternalRefresh(LinksetRoot);
210
211 return ret;
212 }
213
214 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
215 // this routine will restore the removed constraints.
216 // Called at taint-time!!
217 public override void RestoreBodyDependencies(BSPrim child)
218 {
219 }
220
221 // When the linkset is built, the child shape is added to the compound shape relative to the
222 // root shape. The linkset then moves around but this does not move the actual child
223 // prim. The child prim's location must be recomputed based on the location of the root shape.
224 private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
225 {
226 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
227 if (lci != null)
228 {
229 if (inTaintTime)
230 {
231 OMV.Vector3 oldPos = child.RawPosition;
232 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos;
233 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
234 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
235 child.LocalID, oldPos, lci, child.RawPosition);
236 }
237 else
238 {
239 // TaintedObject is not used here so the raw position is set now and not at taint-time.
240 child.Position = LinksetRoot.RawPosition + lci.OffsetPos;
241 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
242 }
243 }
244 else
245 {
246 // This happens when children have been added to the linkset but the linkset
247 // has not been constructed yet. So like, at taint time, adding children to a linkset
248 // and then changing properties of the children (makePhysical, for instance)
249 // but the post-print action of actually rebuilding the linkset has not yet happened.
250 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
251 // LogHeader, child.LocalID);
252 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
253 }
254 }
255
256 // ================================================================
257
258 // Add a new child to the linkset.
259 // Called while LinkActivity is locked.
260 protected override void AddChildToLinkset(BSPhysObject child)
261 {
262 if (!HasChild(child))
263 {
264 m_children.Add(child);
265
266 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
267
268 // Rebuild the compound shape with the new child shape included
269 ScheduleRebuild(child);
270 }
271 return;
272 }
273
274 // Remove the specified child from the linkset.
275 // Safe to call even if the child is not really in the linkset.
276 protected override void RemoveChildFromLinkset(BSPhysObject child)
277 {
278 if (m_children.Remove(child))
279 {
280 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
281 child.LocalID,
282 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(),
283 child.LocalID, child.PhysBody.ptr.ToString());
284
285 // Cause the child's body to be rebuilt and thus restored to normal operation
286 RecomputeChildWorldPosition(child, false);
287 child.ForceBodyShapeRebuild(false);
288
289 if (!HasAnyChildren)
290 {
291 // The linkset is now empty. The root needs rebuilding.
292 LinksetRoot.ForceBodyShapeRebuild(false);
293 }
294 else
295 {
296 // Rebuild the compound shape with the child removed
297 ScheduleRebuild(child);
298 }
299 }
300 return;
301 }
302
303 // Called before the simulation step to make sure the compound based linkset
304 // is all initialized.
305 // Constraint linksets are rebuilt every time.
306 // Note that this works for rebuilding just the root after a linkset is taken apart.
307 // Called at taint time!!
308 private void RecomputeLinksetCompound()
309 {
310 try
311 {
312 // Suppress rebuilding while rebuilding
313 Rebuilding = true;
314
315 // Cause the root shape to be rebuilt as a compound object with just the root in it
316 LinksetRoot.ForceBodyShapeRebuild(true);
317
318 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
319 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
320
321 // Add a shape for each of the other children in the linkset
322 ForEachMember(delegate(BSPhysObject cPrim)
323 {
324 if (!IsRoot(cPrim))
325 {
326 // Compute the displacement of the child from the root of the linkset.
327 // This info is saved in the child prim so the relationship does not
328 // change over time and the new child position can be computed
329 // when the linkset is being disassembled (the linkset may have moved).
330 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
331 if (lci == null)
332 {
333 // Each child position and rotation is given relative to the root.
334 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
335 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
336 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
337
338 // Save relative position for recomputing child's world position after moving linkset.
339 lci = new BSLinksetCompoundInfo(displacementPos, displacementRot);
340 cPrim.LinksetInfo = lci;
341 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
342 }
343
344 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
345 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
346
347 if (cPrim.PhysShape.isNativeShape)
348 {
349 // A native shape is turning into a hull collision shape because native
350 // shapes are not shared so we have to hullify it so it will be tracked
351 // and freed at the correct time. This also solves the scaling problem
352 // (native shapes scaled but hull/meshes are assumed to not be).
353 // TODO: decide of the native shape can just be used in the compound shape.
354 // Use call to CreateGeomNonSpecial().
355 BulletShape saveShape = cPrim.PhysShape;
356 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
357 // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
358 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
359 BulletShape newShape = cPrim.PhysShape;
360 cPrim.PhysShape = saveShape;
361 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos, lci.OffsetRot);
362 }
363 else
364 {
365 // For the shared shapes (meshes and hulls), just use the shape in the child.
366 // The reference count added here will be decremented when the compound shape
367 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
368 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
369 {
370 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
371 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
372 }
373 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos, lci.OffsetRot);
374 }
375 }
376 return false; // 'false' says to move onto the next child in the list
377 });
378
379 // With all of the linkset packed into the root prim, it has the mass of everyone.
380 float linksetMass = LinksetMass;
381 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
382 }
383 finally
384 {
385 Rebuilding = false;
386 }
387
388 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr);
389
390 // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets.
391 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
392 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
393
394 }
395}
396} \ No newline at end of file