diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs new file mode 100755 index 0000000..3238c85 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -0,0 +1,275 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OMV = OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | public sealed class BSLinksetCompound : BSLinkset | ||
36 | { | ||
37 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; | ||
38 | |||
39 | public BSLinksetCompound(BSScene scene, BSPhysObject parent) | ||
40 | { | ||
41 | base.Initialize(scene, parent); | ||
42 | } | ||
43 | |||
44 | // For compound implimented linksets, if there are children, use compound shape for the root. | ||
45 | public override ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | ||
46 | { | ||
47 | ShapeData.PhysicsShapeType ret = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; | ||
48 | if (IsRoot(requestor) && HasAnyChildren) | ||
49 | { | ||
50 | ret = ShapeData.PhysicsShapeType.SHAPE_COMPOUND; | ||
51 | } | ||
52 | // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); | ||
53 | return ret; | ||
54 | } | ||
55 | |||
56 | // When physical properties are changed the linkset needs to recalculate | ||
57 | // its internal properties. | ||
58 | // This is queued in the 'post taint' queue so the | ||
59 | // refresh will happen once after all the other taints are applied. | ||
60 | public override void Refresh(BSPhysObject requestor) | ||
61 | { | ||
62 | // External request for Refresh (from BSPrim) is not necessary | ||
63 | // InternalRefresh(requestor); | ||
64 | } | ||
65 | |||
66 | private void InternalRefresh(BSPhysObject requestor) | ||
67 | { | ||
68 | DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); | ||
69 | // Queue to happen after all the other taint processing | ||
70 | PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() | ||
71 | { | ||
72 | if (IsRoot(requestor) && HasAnyChildren) | ||
73 | RecomputeLinksetCompound(); | ||
74 | }); | ||
75 | } | ||
76 | |||
77 | // The object is going dynamic (physical). Do any setup necessary | ||
78 | // for a dynamic linkset. | ||
79 | // Only the state of the passed object can be modified. The rest of the linkset | ||
80 | // has not yet been fully constructed. | ||
81 | // Return 'true' if any properties updated on the passed object. | ||
82 | // Called at taint-time! | ||
83 | public override bool MakeDynamic(BSPhysObject child) | ||
84 | { | ||
85 | bool ret = false; | ||
86 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
87 | if (!IsRoot(child)) | ||
88 | { | ||
89 | // Physical children are removed from the world as the shape ofthe root compound | ||
90 | // shape takes over. | ||
91 | BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
92 | BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | ||
93 | ret = true; | ||
94 | } | ||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | // The object is going static (non-physical). Do any setup necessary for a static linkset. | ||
99 | // Return 'true' if any properties updated on the passed object. | ||
100 | // This doesn't normally happen -- OpenSim removes the objects from the physical | ||
101 | // world if it is a static linkset. | ||
102 | // Called at taint-time! | ||
103 | public override bool MakeStatic(BSPhysObject child) | ||
104 | { | ||
105 | bool ret = false; | ||
106 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
107 | if (!IsRoot(child)) | ||
108 | { | ||
109 | // The non-physical children can come back to life. | ||
110 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
111 | // Don't force activation so setting of DISABLE_SIMULATION can stay. | ||
112 | BulletSimAPI.Activate2(child.PhysBody.ptr, false); | ||
113 | ret = true; | ||
114 | } | ||
115 | return ret; | ||
116 | } | ||
117 | |||
118 | // Called at taint-time!! | ||
119 | public override void UpdateProperties(BSPhysObject updated) | ||
120 | { | ||
121 | // Nothing to do for constraints on property updates | ||
122 | } | ||
123 | |||
124 | // The children move around in relationship to the root. | ||
125 | // Just grab the current values of wherever it is right now. | ||
126 | public override OMV.Vector3 Position(BSPhysObject member) | ||
127 | { | ||
128 | return BulletSimAPI.GetPosition2(member.PhysBody.ptr); | ||
129 | } | ||
130 | |||
131 | public override OMV.Quaternion Orientation(BSPhysObject member) | ||
132 | { | ||
133 | return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); | ||
134 | } | ||
135 | |||
136 | // Routine called when rebuilding the body of some member of the linkset. | ||
137 | // Since we don't keep in world relationships, do nothing unless it's a child changing. | ||
138 | // Returns 'true' of something was actually removed and would need restoring | ||
139 | // Called at taint-time!! | ||
140 | public override bool RemoveBodyDependencies(BSPrim child) | ||
141 | { | ||
142 | bool ret = false; | ||
143 | |||
144 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", | ||
145 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child)); | ||
146 | |||
147 | if (!IsRoot(child)) | ||
148 | { | ||
149 | // Cause the current shape to be freed and the new one to be built. | ||
150 | InternalRefresh(LinksetRoot); | ||
151 | ret = true; | ||
152 | } | ||
153 | |||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | ||
158 | // this routine will restore the removed constraints. | ||
159 | // Called at taint-time!! | ||
160 | public override void RestoreBodyDependencies(BSPrim child) | ||
161 | { | ||
162 | // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. | ||
163 | } | ||
164 | |||
165 | // ================================================================ | ||
166 | |||
167 | // Add a new child to the linkset. | ||
168 | // Called while LinkActivity is locked. | ||
169 | protected override void AddChildToLinkset(BSPhysObject child) | ||
170 | { | ||
171 | if (!HasChild(child)) | ||
172 | { | ||
173 | m_children.Add(child); | ||
174 | |||
175 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | ||
176 | |||
177 | // Cause constraints and assorted properties to be recomputed before the next simulation step. | ||
178 | InternalRefresh(LinksetRoot); | ||
179 | } | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | // Remove the specified child from the linkset. | ||
184 | // Safe to call even if the child is not really in my linkset. | ||
185 | protected override void RemoveChildFromLinkset(BSPhysObject child) | ||
186 | { | ||
187 | if (m_children.Remove(child)) | ||
188 | { | ||
189 | DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | ||
190 | child.LocalID, | ||
191 | LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), | ||
192 | child.LocalID, child.PhysBody.ptr.ToString("X")); | ||
193 | |||
194 | // Cause the child's body to be rebuilt and thus restored to normal operation | ||
195 | child.ForceBodyShapeRebuild(false); | ||
196 | |||
197 | if (!HasAnyChildren) | ||
198 | { | ||
199 | // The linkset is now empty. The root needs rebuilding. | ||
200 | LinksetRoot.ForceBodyShapeRebuild(false); | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | // Schedule a rebuild of the linkset before the next simulation tick. | ||
205 | InternalRefresh(LinksetRoot); | ||
206 | } | ||
207 | } | ||
208 | return; | ||
209 | } | ||
210 | |||
211 | // Called before the simulation step to make sure the compound based linkset | ||
212 | // is all initialized. | ||
213 | // Constraint linksets are rebuilt every time. | ||
214 | // Note that this works for rebuilding just the root after a linkset is taken apart. | ||
215 | // Called at taint time!! | ||
216 | private void RecomputeLinksetCompound() | ||
217 | { | ||
218 | // Cause the root shape to be rebuilt as a compound object with just the root in it | ||
219 | LinksetRoot.ForceBodyShapeRebuild(true); | ||
220 | |||
221 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | ||
222 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | ||
223 | |||
224 | // Add a shape for each of the other children in the linkset | ||
225 | ForEachMember(delegate(BSPhysObject cPrim) | ||
226 | { | ||
227 | if (!IsRoot(cPrim)) | ||
228 | { | ||
229 | // Each child position and rotation is given relative to the root. | ||
230 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | ||
231 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | ||
232 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | ||
233 | |||
234 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", | ||
235 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); | ||
236 | |||
237 | if (cPrim.PhysShape.isNativeShape) | ||
238 | { | ||
239 | // Native shapes are not shared so we need to create a new one. | ||
240 | // A mesh or hull is created because scale is not available on a native shape. | ||
241 | // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?) | ||
242 | BulletShape saveShape = cPrim.PhysShape; | ||
243 | cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape | ||
244 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | ||
245 | BulletShape newShape = cPrim.PhysShape; | ||
246 | cPrim.PhysShape = saveShape; | ||
247 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot); | ||
248 | } | ||
249 | else | ||
250 | { | ||
251 | // For the shared shapes (meshes and hulls), just use the shape in the child. | ||
252 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | ||
253 | { | ||
254 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | ||
255 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | ||
256 | } | ||
257 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot); | ||
258 | } | ||
259 | } | ||
260 | return false; // 'false' says to move onto the next child in the list | ||
261 | }); | ||
262 | |||
263 | // With all of the linkset packed into the root prim, it has the mass of everyone. | ||
264 | float linksetMass = LinksetMass; | ||
265 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass); | ||
266 | |||
267 | BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); | ||
268 | |||
269 | // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets. | ||
270 | // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, | ||
271 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); | ||
272 | |||
273 | } | ||
274 | } | ||
275 | } \ No newline at end of file | ||