diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 88 |
1 files changed, 73 insertions, 15 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index fc04761..52469a2 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -451,6 +451,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
451 | } | 451 | } |
452 | } | 452 | } |
453 | 453 | ||
454 | // Restuff the new GroupPosition into each SOP of the linkset. | ||
455 | // This has the affect of resetting and tainting the physics actors. | ||
454 | SceneObjectPart[] parts = m_parts.GetArray(); | 456 | SceneObjectPart[] parts = m_parts.GetArray(); |
455 | for (int i = 0; i < parts.Length; i++) | 457 | for (int i = 0; i < parts.Length; i++) |
456 | parts[i].GroupPosition = val; | 458 | parts[i].GroupPosition = val; |
@@ -1133,6 +1135,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
1133 | 1135 | ||
1134 | public void ResetChildPrimPhysicsPositions() | 1136 | public void ResetChildPrimPhysicsPositions() |
1135 | { | 1137 | { |
1138 | // Setting this SOG's absolute position also loops through and sets the positions | ||
1139 | // of the SOP's in this SOG's linkset. This has the side affect of making sure | ||
1140 | // the physics world matches the simulated world. | ||
1136 | AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works? | 1141 | AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works? |
1137 | 1142 | ||
1138 | // teravus: AbsolutePosition is NOT a normal property! | 1143 | // teravus: AbsolutePosition is NOT a normal property! |
@@ -1987,6 +1992,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1987 | LinkToGroup(objectGroup, false); | 1992 | LinkToGroup(objectGroup, false); |
1988 | } | 1993 | } |
1989 | 1994 | ||
1995 | // Link an existing group to this group. | ||
1996 | // The group being linked need not be a linkset -- it can have just one prim. | ||
1990 | public void LinkToGroup(SceneObjectGroup objectGroup, bool insert) | 1997 | public void LinkToGroup(SceneObjectGroup objectGroup, bool insert) |
1991 | { | 1998 | { |
1992 | // m_log.DebugFormat( | 1999 | // m_log.DebugFormat( |
@@ -1997,35 +2004,51 @@ namespace OpenSim.Region.Framework.Scenes | |||
1997 | if (objectGroup == this) | 2004 | if (objectGroup == this) |
1998 | return; | 2005 | return; |
1999 | 2006 | ||
2007 | // 'linkPart' == the root of the group being linked into this group | ||
2000 | SceneObjectPart linkPart = objectGroup.m_rootPart; | 2008 | SceneObjectPart linkPart = objectGroup.m_rootPart; |
2001 | 2009 | ||
2002 | // physics flags from group to be applied to linked parts | 2010 | // physics flags from group to be applied to linked parts |
2003 | bool grpusephys = UsesPhysics; | 2011 | bool grpusephys = UsesPhysics; |
2004 | bool grptemporary = IsTemporary; | 2012 | bool grptemporary = IsTemporary; |
2005 | 2013 | ||
2014 | // Remember where the group being linked thought it was | ||
2006 | Vector3 oldGroupPosition = linkPart.GroupPosition; | 2015 | Vector3 oldGroupPosition = linkPart.GroupPosition; |
2007 | Quaternion oldRootRotation = linkPart.RotationOffset; | 2016 | Quaternion oldRootRotation = linkPart.RotationOffset; |
2008 | 2017 | ||
2018 | // A linked SOP remembers its location and rotation relative to the root of a group. | ||
2019 | // Convert the root of the group being linked to be relative to the | ||
2020 | // root of the group being linked to. | ||
2021 | // Note: Some of the assignments have complex side effects. | ||
2022 | |||
2023 | // First move the new group's root SOP's position to be relative to ours | ||
2024 | // (radams1: Not sure if the multiple setting of OffsetPosition is required. If not, | ||
2025 | // this code can be reordered to have a more logical flow.) | ||
2009 | linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; | 2026 | linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; |
2027 | // Assign the new parent to the root of the old group | ||
2010 | linkPart.ParentID = m_rootPart.LocalId; | 2028 | linkPart.ParentID = m_rootPart.LocalId; |
2029 | // Now that it's a child, it's group position is our root position | ||
2011 | linkPart.GroupPosition = AbsolutePosition; | 2030 | linkPart.GroupPosition = AbsolutePosition; |
2012 | Vector3 axPos = linkPart.OffsetPosition; | ||
2013 | 2031 | ||
2032 | Vector3 axPos = linkPart.OffsetPosition; | ||
2033 | // Rotate the linking root SOP's position to be relative to the new root prim | ||
2014 | Quaternion parentRot = m_rootPart.RotationOffset; | 2034 | Quaternion parentRot = m_rootPart.RotationOffset; |
2015 | axPos *= Quaternion.Inverse(parentRot); | 2035 | axPos *= Quaternion.Inverse(parentRot); |
2016 | |||
2017 | linkPart.OffsetPosition = axPos; | 2036 | linkPart.OffsetPosition = axPos; |
2037 | |||
2038 | // Make the linking root SOP's rotation relative to the new root prim | ||
2018 | Quaternion oldRot = linkPart.RotationOffset; | 2039 | Quaternion oldRot = linkPart.RotationOffset; |
2019 | Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; | 2040 | Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; |
2020 | linkPart.RotationOffset = newRot; | 2041 | linkPart.RotationOffset = newRot; |
2021 | 2042 | ||
2022 | linkPart.ParentID = m_rootPart.LocalId; | 2043 | // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. |
2023 | 2044 | // Now that we know this SOG has at least two SOPs in it, the new root | |
2045 | // SOP becomes the first in the linkset. | ||
2024 | if (m_rootPart.LinkNum == 0) | 2046 | if (m_rootPart.LinkNum == 0) |
2025 | m_rootPart.LinkNum = 1; | 2047 | m_rootPart.LinkNum = 1; |
2026 | 2048 | ||
2027 | lock (m_parts.SyncRoot) | 2049 | lock (m_parts.SyncRoot) |
2028 | { | 2050 | { |
2051 | // Calculate the new link number for the old root SOP | ||
2029 | int linkNum; | 2052 | int linkNum; |
2030 | if (insert) | 2053 | if (insert) |
2031 | { | 2054 | { |
@@ -2041,6 +2064,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2041 | linkNum = PrimCount + 1; | 2064 | linkNum = PrimCount + 1; |
2042 | } | 2065 | } |
2043 | 2066 | ||
2067 | // Add the old root SOP as a part in our group's list | ||
2044 | m_parts.Add(linkPart.UUID, linkPart); | 2068 | m_parts.Add(linkPart.UUID, linkPart); |
2045 | 2069 | ||
2046 | linkPart.SetParent(this); | 2070 | linkPart.SetParent(this); |
@@ -2048,6 +2072,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2048 | 2072 | ||
2049 | // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now | 2073 | // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now |
2050 | linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); | 2074 | linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); |
2075 | |||
2076 | // If the added SOP is physical, also tell the physics engine about the link relationship. | ||
2051 | if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) | 2077 | if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) |
2052 | { | 2078 | { |
2053 | linkPart.PhysActor.link(m_rootPart.PhysActor); | 2079 | linkPart.PhysActor.link(m_rootPart.PhysActor); |
@@ -2056,20 +2082,26 @@ namespace OpenSim.Region.Framework.Scenes | |||
2056 | 2082 | ||
2057 | linkPart.LinkNum = linkNum++; | 2083 | linkPart.LinkNum = linkNum++; |
2058 | 2084 | ||
2085 | // Get a list of the SOP's in the old group in order of their linknum's. | ||
2059 | SceneObjectPart[] ogParts = objectGroup.Parts; | 2086 | SceneObjectPart[] ogParts = objectGroup.Parts; |
2060 | Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) | 2087 | Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) |
2061 | { | 2088 | { |
2062 | return a.LinkNum - b.LinkNum; | 2089 | return a.LinkNum - b.LinkNum; |
2063 | }); | 2090 | }); |
2064 | 2091 | ||
2092 | // Add each of the SOP's from the old linkset to our linkset | ||
2065 | for (int i = 0; i < ogParts.Length; i++) | 2093 | for (int i = 0; i < ogParts.Length; i++) |
2066 | { | 2094 | { |
2067 | SceneObjectPart part = ogParts[i]; | 2095 | SceneObjectPart part = ogParts[i]; |
2068 | if (part.UUID != objectGroup.m_rootPart.UUID) | 2096 | if (part.UUID != objectGroup.m_rootPart.UUID) |
2069 | { | 2097 | { |
2070 | LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); | 2098 | LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); |
2071 | // let physics know | 2099 | |
2100 | // Update the physics flags for the newly added SOP | ||
2101 | // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) | ||
2072 | part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); | 2102 | part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); |
2103 | |||
2104 | // If the added SOP is physical, also tell the physics engine about the link relationship. | ||
2073 | if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) | 2105 | if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) |
2074 | { | 2106 | { |
2075 | part.PhysActor.link(m_rootPart.PhysActor); | 2107 | part.PhysActor.link(m_rootPart.PhysActor); |
@@ -2080,6 +2112,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2080 | } | 2112 | } |
2081 | } | 2113 | } |
2082 | 2114 | ||
2115 | // Now that we've aquired all of the old SOG's parts, remove the old SOG from the scene. | ||
2083 | m_scene.UnlinkSceneObject(objectGroup, true); | 2116 | m_scene.UnlinkSceneObject(objectGroup, true); |
2084 | objectGroup.IsDeleted = true; | 2117 | objectGroup.IsDeleted = true; |
2085 | 2118 | ||
@@ -2152,7 +2185,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2152 | /// <remarks> | 2185 | /// <remarks> |
2153 | /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race | 2186 | /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race |
2154 | /// condition. But currently there is no | 2187 | /// condition. But currently there is no |
2155 | /// alternative method that does take a lonk to delink a single prim. | 2188 | /// alternative method that does take a lock to delink a single prim. |
2156 | /// </remarks> | 2189 | /// </remarks> |
2157 | /// <param name="partID"></param> | 2190 | /// <param name="partID"></param> |
2158 | /// <param name="sendEvents"></param> | 2191 | /// <param name="sendEvents"></param> |
@@ -2165,6 +2198,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2165 | 2198 | ||
2166 | linkPart.ClearUndoState(); | 2199 | linkPart.ClearUndoState(); |
2167 | 2200 | ||
2201 | Vector3 worldPos = linkPart.GetWorldPosition(); | ||
2168 | Quaternion worldRot = linkPart.GetWorldRotation(); | 2202 | Quaternion worldRot = linkPart.GetWorldRotation(); |
2169 | 2203 | ||
2170 | // Remove the part from this object | 2204 | // Remove the part from this object |
@@ -2174,6 +2208,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2174 | 2208 | ||
2175 | SceneObjectPart[] parts = m_parts.GetArray(); | 2209 | SceneObjectPart[] parts = m_parts.GetArray(); |
2176 | 2210 | ||
2211 | // Rejigger the linknum's of the remaining SOP's to fill any gap | ||
2177 | if (parts.Length == 1 && RootPart != null) | 2212 | if (parts.Length == 1 && RootPart != null) |
2178 | { | 2213 | { |
2179 | // Single prim left | 2214 | // Single prim left |
@@ -2195,22 +2230,31 @@ namespace OpenSim.Region.Framework.Scenes | |||
2195 | 2230 | ||
2196 | PhysicsActor linkPartPa = linkPart.PhysActor; | 2231 | PhysicsActor linkPartPa = linkPart.PhysActor; |
2197 | 2232 | ||
2233 | // Remove the SOP from the physical scene. | ||
2234 | // If the new SOG is physical, it is re-created later. | ||
2235 | // (There is a problem here in that we have not yet told the physics | ||
2236 | // engine about the delink. Someday, linksets should be made first | ||
2237 | // class objects in the physics engine interface). | ||
2198 | if (linkPartPa != null) | 2238 | if (linkPartPa != null) |
2199 | m_scene.PhysicsScene.RemovePrim(linkPartPa); | 2239 | m_scene.PhysicsScene.RemovePrim(linkPartPa); |
2200 | 2240 | ||
2201 | // We need to reset the child part's position | 2241 | // We need to reset the child part's position |
2202 | // ready for life as a separate object after being a part of another object | 2242 | // ready for life as a separate object after being a part of another object |
2203 | Quaternion parentRot = m_rootPart.RotationOffset; | ||
2204 | 2243 | ||
2244 | /* This commented out code seems to recompute what GetWorldPosition already does. | ||
2245 | * Replace with a call to GetWorldPosition (before unlinking) | ||
2246 | Quaternion parentRot = m_rootPart.RotationOffset; | ||
2205 | Vector3 axPos = linkPart.OffsetPosition; | 2247 | Vector3 axPos = linkPart.OffsetPosition; |
2206 | |||
2207 | axPos *= parentRot; | 2248 | axPos *= parentRot; |
2208 | linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); | 2249 | linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); |
2209 | linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; | 2250 | linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; |
2210 | linkPart.OffsetPosition = new Vector3(0, 0, 0); | 2251 | linkPart.OffsetPosition = new Vector3(0, 0, 0); |
2211 | 2252 | */ | |
2253 | linkPart.GroupPosition = worldPos; | ||
2254 | linkPart.OffsetPosition = Vector3.Zero; | ||
2212 | linkPart.RotationOffset = worldRot; | 2255 | linkPart.RotationOffset = worldRot; |
2213 | 2256 | ||
2257 | // Create a new SOG to go around this unlinked and unattached SOP | ||
2214 | SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); | 2258 | SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); |
2215 | 2259 | ||
2216 | m_scene.AddNewSceneObject(objectGroup, true); | 2260 | m_scene.AddNewSceneObject(objectGroup, true); |
@@ -2239,42 +2283,56 @@ namespace OpenSim.Region.Framework.Scenes | |||
2239 | m_isBackedUp = false; | 2283 | m_isBackedUp = false; |
2240 | } | 2284 | } |
2241 | 2285 | ||
2286 | // This links an SOP from a previous linkset into my linkset. | ||
2287 | // The trick is that the SOP's position and rotation are relative to the old root SOP's | ||
2288 | // so we are passed in the position and rotation of the old linkset so this can | ||
2289 | // unjigger this SOP's position and rotation from the previous linkset and | ||
2290 | // then make them relative to my linkset root. | ||
2242 | private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum) | 2291 | private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum) |
2243 | { | 2292 | { |
2244 | Quaternion parentRot = oldGroupRotation; | 2293 | Quaternion parentRot = oldGroupRotation; |
2245 | Quaternion oldRot = part.RotationOffset; | 2294 | Quaternion oldRot = part.RotationOffset; |
2246 | Quaternion worldRot = parentRot * oldRot; | ||
2247 | |||
2248 | parentRot = oldGroupRotation; | ||
2249 | 2295 | ||
2296 | // Move our position to not be relative to the old parent | ||
2250 | Vector3 axPos = part.OffsetPosition; | 2297 | Vector3 axPos = part.OffsetPosition; |
2251 | |||
2252 | axPos *= parentRot; | 2298 | axPos *= parentRot; |
2253 | part.OffsetPosition = axPos; | 2299 | part.OffsetPosition = axPos; |
2254 | part.GroupPosition = oldGroupPosition + part.OffsetPosition; | 2300 | part.GroupPosition = oldGroupPosition + part.OffsetPosition; |
2255 | part.OffsetPosition = Vector3.Zero; | 2301 | part.OffsetPosition = Vector3.Zero; |
2302 | |||
2303 | // Compution our rotation to be not relative to the old parent | ||
2304 | Quaternion worldRot = parentRot * oldRot; | ||
2256 | part.RotationOffset = worldRot; | 2305 | part.RotationOffset = worldRot; |
2257 | 2306 | ||
2307 | // Add this SOP to our linkset | ||
2258 | part.SetParent(this); | 2308 | part.SetParent(this); |
2259 | part.ParentID = m_rootPart.LocalId; | 2309 | part.ParentID = m_rootPart.LocalId; |
2260 | |||
2261 | m_parts.Add(part.UUID, part); | 2310 | m_parts.Add(part.UUID, part); |
2262 | 2311 | ||
2263 | part.LinkNum = linkNum; | 2312 | part.LinkNum = linkNum; |
2264 | 2313 | ||
2314 | // Compute the new position of this SOP relative to the group position | ||
2265 | part.OffsetPosition = part.GroupPosition - AbsolutePosition; | 2315 | part.OffsetPosition = part.GroupPosition - AbsolutePosition; |
2266 | 2316 | ||
2267 | Quaternion rootRotation = m_rootPart.RotationOffset; | 2317 | // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. |
2318 | // It would have the affect of setting the physics engine position multiple | ||
2319 | // times. In theory, that is not necessary but I don't have a good linkset | ||
2320 | // test to know that cleaning up this code wouldn't break things.) | ||
2268 | 2321 | ||
2322 | // Rotate the relative position by the rotation of the group | ||
2323 | Quaternion rootRotation = m_rootPart.RotationOffset; | ||
2269 | Vector3 pos = part.OffsetPosition; | 2324 | Vector3 pos = part.OffsetPosition; |
2270 | pos *= Quaternion.Inverse(rootRotation); | 2325 | pos *= Quaternion.Inverse(rootRotation); |
2271 | part.OffsetPosition = pos; | 2326 | part.OffsetPosition = pos; |
2272 | 2327 | ||
2328 | // Compute the SOP's rotation relative to the rotation of the group. | ||
2273 | parentRot = m_rootPart.RotationOffset; | 2329 | parentRot = m_rootPart.RotationOffset; |
2274 | oldRot = part.RotationOffset; | 2330 | oldRot = part.RotationOffset; |
2275 | Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; | 2331 | Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; |
2276 | part.RotationOffset = newRot; | 2332 | part.RotationOffset = newRot; |
2277 | 2333 | ||
2334 | // Since this SOP's state has changed, push those changes into the physics engine | ||
2335 | // and the simulator. | ||
2278 | part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); | 2336 | part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); |
2279 | } | 2337 | } |
2280 | 2338 | ||