diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 91 |
1 files changed, 74 insertions, 17 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index cc7d0fb..33a2cc5 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -646,6 +646,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
646 | return; | 646 | return; |
647 | } | 647 | } |
648 | } | 648 | } |
649 | |||
650 | // Restuff the new GroupPosition into each SOP of the linkset. | ||
651 | // This has the affect of resetting and tainting the physics actors. | ||
649 | SceneObjectPart[] parts = m_parts.GetArray(); | 652 | SceneObjectPart[] parts = m_parts.GetArray(); |
650 | bool triggerScriptEvent = m_rootPart.GroupPosition != val; | 653 | bool triggerScriptEvent = m_rootPart.GroupPosition != val; |
651 | if (m_dupeInProgress) | 654 | if (m_dupeInProgress) |
@@ -1755,6 +1758,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
1755 | 1758 | ||
1756 | public void ResetChildPrimPhysicsPositions() | 1759 | public void ResetChildPrimPhysicsPositions() |
1757 | { | 1760 | { |
1761 | // Setting this SOG's absolute position also loops through and sets the positions | ||
1762 | // of the SOP's in this SOG's linkset. This has the side affect of making sure | ||
1763 | // the physics world matches the simulated world. | ||
1758 | AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works? | 1764 | AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works? |
1759 | 1765 | ||
1760 | // teravus: AbsolutePosition is NOT a normal property! | 1766 | // teravus: AbsolutePosition is NOT a normal property! |
@@ -2714,6 +2720,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2714 | LinkToGroup(objectGroup, false); | 2720 | LinkToGroup(objectGroup, false); |
2715 | } | 2721 | } |
2716 | 2722 | ||
2723 | // Link an existing group to this group. | ||
2724 | // The group being linked need not be a linkset -- it can have just one prim. | ||
2717 | public void LinkToGroup(SceneObjectGroup objectGroup, bool insert) | 2725 | public void LinkToGroup(SceneObjectGroup objectGroup, bool insert) |
2718 | { | 2726 | { |
2719 | // m_log.DebugFormat( | 2727 | // m_log.DebugFormat( |
@@ -2724,6 +2732,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2724 | if (objectGroup == this) | 2732 | if (objectGroup == this) |
2725 | return; | 2733 | return; |
2726 | 2734 | ||
2735 | // 'linkPart' == the root of the group being linked into this group | ||
2727 | SceneObjectPart linkPart = objectGroup.m_rootPart; | 2736 | SceneObjectPart linkPart = objectGroup.m_rootPart; |
2728 | 2737 | ||
2729 | if (m_rootPart.PhysActor != null) | 2738 | if (m_rootPart.PhysActor != null) |
@@ -2735,31 +2744,44 @@ namespace OpenSim.Region.Framework.Scenes | |||
2735 | bool grpusephys = UsesPhysics; | 2744 | bool grpusephys = UsesPhysics; |
2736 | bool grptemporary = IsTemporary; | 2745 | bool grptemporary = IsTemporary; |
2737 | 2746 | ||
2747 | // Remember where the group being linked thought it was | ||
2738 | Vector3 oldGroupPosition = linkPart.GroupPosition; | 2748 | Vector3 oldGroupPosition = linkPart.GroupPosition; |
2739 | Quaternion oldRootRotation = linkPart.RotationOffset; | 2749 | Quaternion oldRootRotation = linkPart.RotationOffset; |
2740 | 2750 | ||
2741 | linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; | 2751 | // A linked SOP remembers its location and rotation relative to the root of a group. |
2752 | // Convert the root of the group being linked to be relative to the | ||
2753 | // root of the group being linked to. | ||
2754 | // Note: Some of the assignments have complex side effects. | ||
2742 | 2755 | ||
2756 | // First move the new group's root SOP's position to be relative to ours | ||
2757 | // (radams1: Not sure if the multiple setting of OffsetPosition is required. If not, | ||
2758 | // this code can be reordered to have a more logical flow.) | ||
2759 | linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; | ||
2760 | // Assign the new parent to the root of the old group | ||
2743 | linkPart.ParentID = m_rootPart.LocalId; | 2761 | linkPart.ParentID = m_rootPart.LocalId; |
2744 | 2762 | // Now that it's a child, it's group position is our root position | |
2745 | linkPart.GroupPosition = AbsolutePosition; | 2763 | linkPart.GroupPosition = AbsolutePosition; |
2746 | 2764 | ||
2747 | Vector3 axPos = linkPart.OffsetPosition; | 2765 | Vector3 axPos = linkPart.OffsetPosition; |
2766 | // Rotate the linking root SOP's position to be relative to the new root prim | ||
2748 | Quaternion parentRot = m_rootPart.RotationOffset; | 2767 | Quaternion parentRot = m_rootPart.RotationOffset; |
2749 | axPos *= Quaternion.Conjugate(parentRot); | 2768 | axPos *= Quaternion.Conjugate(parentRot); |
2750 | linkPart.OffsetPosition = axPos; | 2769 | linkPart.OffsetPosition = axPos; |
2751 | 2770 | ||
2771 | // Make the linking root SOP's rotation relative to the new root prim | ||
2752 | Quaternion oldRot = linkPart.RotationOffset; | 2772 | Quaternion oldRot = linkPart.RotationOffset; |
2753 | Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot; | 2773 | Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot; |
2754 | linkPart.RotationOffset = newRot; | 2774 | linkPart.RotationOffset = newRot; |
2755 | 2775 | ||
2756 | // linkPart.ParentID = m_rootPart.LocalId; done above | 2776 | // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. |
2757 | 2777 | // Now that we know this SOG has at least two SOPs in it, the new root | |
2778 | // SOP becomes the first in the linkset. | ||
2758 | if (m_rootPart.LinkNum == 0) | 2779 | if (m_rootPart.LinkNum == 0) |
2759 | m_rootPart.LinkNum = 1; | 2780 | m_rootPart.LinkNum = 1; |
2760 | 2781 | ||
2761 | lock (m_parts.SyncRoot) | 2782 | lock (m_parts.SyncRoot) |
2762 | { | 2783 | { |
2784 | // Calculate the new link number for the old root SOP | ||
2763 | int linkNum; | 2785 | int linkNum; |
2764 | if (insert) | 2786 | if (insert) |
2765 | { | 2787 | { |
@@ -2775,6 +2797,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2775 | linkNum = PrimCount + 1; | 2797 | linkNum = PrimCount + 1; |
2776 | } | 2798 | } |
2777 | 2799 | ||
2800 | // Add the old root SOP as a part in our group's list | ||
2778 | m_parts.Add(linkPart.UUID, linkPart); | 2801 | m_parts.Add(linkPart.UUID, linkPart); |
2779 | 2802 | ||
2780 | linkPart.SetParent(this); | 2803 | linkPart.SetParent(this); |
@@ -2782,6 +2805,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2782 | 2805 | ||
2783 | // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now | 2806 | // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now |
2784 | linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true); | 2807 | linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true); |
2808 | |||
2809 | // If the added SOP is physical, also tell the physics engine about the link relationship. | ||
2785 | if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) | 2810 | if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) |
2786 | { | 2811 | { |
2787 | linkPart.PhysActor.link(m_rootPart.PhysActor); | 2812 | linkPart.PhysActor.link(m_rootPart.PhysActor); |
@@ -2791,20 +2816,26 @@ namespace OpenSim.Region.Framework.Scenes | |||
2791 | linkPart.LinkNum = linkNum++; | 2816 | linkPart.LinkNum = linkNum++; |
2792 | linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false); | 2817 | linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false); |
2793 | 2818 | ||
2819 | // Get a list of the SOP's in the old group in order of their linknum's. | ||
2794 | SceneObjectPart[] ogParts = objectGroup.Parts; | 2820 | SceneObjectPart[] ogParts = objectGroup.Parts; |
2795 | Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) | 2821 | Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) |
2796 | { | 2822 | { |
2797 | return a.LinkNum - b.LinkNum; | 2823 | return a.LinkNum - b.LinkNum; |
2798 | }); | 2824 | }); |
2799 | 2825 | ||
2826 | // Add each of the SOP's from the old linkset to our linkset | ||
2800 | for (int i = 0; i < ogParts.Length; i++) | 2827 | for (int i = 0; i < ogParts.Length; i++) |
2801 | { | 2828 | { |
2802 | SceneObjectPart part = ogParts[i]; | 2829 | SceneObjectPart part = ogParts[i]; |
2803 | if (part.UUID != objectGroup.m_rootPart.UUID) | 2830 | if (part.UUID != objectGroup.m_rootPart.UUID) |
2804 | { | 2831 | { |
2805 | LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); | 2832 | LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); |
2806 | // let physics know | 2833 | |
2834 | // Update the physics flags for the newly added SOP | ||
2835 | // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) | ||
2807 | part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true); | 2836 | part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true); |
2837 | |||
2838 | // If the added SOP is physical, also tell the physics engine about the link relationship. | ||
2808 | if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) | 2839 | if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) |
2809 | { | 2840 | { |
2810 | part.PhysActor.link(m_rootPart.PhysActor); | 2841 | part.PhysActor.link(m_rootPart.PhysActor); |
@@ -2815,6 +2846,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2815 | } | 2846 | } |
2816 | } | 2847 | } |
2817 | 2848 | ||
2849 | // Now that we've aquired all of the old SOG's parts, remove the old SOG from the scene. | ||
2818 | m_scene.UnlinkSceneObject(objectGroup, true); | 2850 | m_scene.UnlinkSceneObject(objectGroup, true); |
2819 | objectGroup.IsDeleted = true; | 2851 | objectGroup.IsDeleted = true; |
2820 | 2852 | ||
@@ -2890,7 +2922,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2890 | /// <remarks> | 2922 | /// <remarks> |
2891 | /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race | 2923 | /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race |
2892 | /// condition. But currently there is no | 2924 | /// condition. But currently there is no |
2893 | /// alternative method that does take a lonk to delink a single prim. | 2925 | /// alternative method that does take a lock to delink a single prim. |
2894 | /// </remarks> | 2926 | /// </remarks> |
2895 | /// <param name="partID"></param> | 2927 | /// <param name="partID"></param> |
2896 | /// <param name="sendEvents"></param> | 2928 | /// <param name="sendEvents"></param> |
@@ -2906,6 +2938,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2906 | 2938 | ||
2907 | linkPart.ClearUndoState(); | 2939 | linkPart.ClearUndoState(); |
2908 | 2940 | ||
2941 | Vector3 worldPos = linkPart.GetWorldPosition(); | ||
2909 | Quaternion worldRot = linkPart.GetWorldRotation(); | 2942 | Quaternion worldRot = linkPart.GetWorldRotation(); |
2910 | 2943 | ||
2911 | // Remove the part from this object | 2944 | // Remove the part from this object |
@@ -2915,6 +2948,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2915 | 2948 | ||
2916 | SceneObjectPart[] parts = m_parts.GetArray(); | 2949 | SceneObjectPart[] parts = m_parts.GetArray(); |
2917 | 2950 | ||
2951 | // Rejigger the linknum's of the remaining SOP's to fill any gap | ||
2918 | if (parts.Length == 1 && RootPart != null) | 2952 | if (parts.Length == 1 && RootPart != null) |
2919 | { | 2953 | { |
2920 | // Single prim left | 2954 | // Single prim left |
@@ -2936,22 +2970,31 @@ namespace OpenSim.Region.Framework.Scenes | |||
2936 | 2970 | ||
2937 | PhysicsActor linkPartPa = linkPart.PhysActor; | 2971 | PhysicsActor linkPartPa = linkPart.PhysActor; |
2938 | 2972 | ||
2973 | // Remove the SOP from the physical scene. | ||
2974 | // If the new SOG is physical, it is re-created later. | ||
2975 | // (There is a problem here in that we have not yet told the physics | ||
2976 | // engine about the delink. Someday, linksets should be made first | ||
2977 | // class objects in the physics engine interface). | ||
2939 | if (linkPartPa != null) | 2978 | if (linkPartPa != null) |
2940 | m_scene.PhysicsScene.RemovePrim(linkPartPa); | 2979 | m_scene.PhysicsScene.RemovePrim(linkPartPa); |
2941 | 2980 | ||
2942 | // We need to reset the child part's position | 2981 | // We need to reset the child part's position |
2943 | // ready for life as a separate object after being a part of another object | 2982 | // ready for life as a separate object after being a part of another object |
2944 | Quaternion parentRot = m_rootPart.RotationOffset; | ||
2945 | 2983 | ||
2984 | /* This commented out code seems to recompute what GetWorldPosition already does. | ||
2985 | * Replace with a call to GetWorldPosition (before unlinking) | ||
2986 | Quaternion parentRot = m_rootPart.RotationOffset; | ||
2946 | Vector3 axPos = linkPart.OffsetPosition; | 2987 | Vector3 axPos = linkPart.OffsetPosition; |
2947 | |||
2948 | axPos *= parentRot; | 2988 | axPos *= parentRot; |
2949 | linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); | 2989 | linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); |
2950 | linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; | 2990 | linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; |
2951 | linkPart.OffsetPosition = new Vector3(0, 0, 0); | 2991 | linkPart.OffsetPosition = new Vector3(0, 0, 0); |
2952 | 2992 | */ | |
2993 | linkPart.GroupPosition = worldPos; | ||
2994 | linkPart.OffsetPosition = Vector3.Zero; | ||
2953 | linkPart.RotationOffset = worldRot; | 2995 | linkPart.RotationOffset = worldRot; |
2954 | 2996 | ||
2997 | // Create a new SOG to go around this unlinked and unattached SOP | ||
2955 | SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); | 2998 | SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); |
2956 | 2999 | ||
2957 | m_scene.AddNewSceneObject(objectGroup, true); | 3000 | m_scene.AddNewSceneObject(objectGroup, true); |
@@ -2989,43 +3032,57 @@ namespace OpenSim.Region.Framework.Scenes | |||
2989 | m_isBackedUp = false; | 3032 | m_isBackedUp = false; |
2990 | } | 3033 | } |
2991 | 3034 | ||
3035 | // This links an SOP from a previous linkset into my linkset. | ||
3036 | // The trick is that the SOP's position and rotation are relative to the old root SOP's | ||
3037 | // so we are passed in the position and rotation of the old linkset so this can | ||
3038 | // unjigger this SOP's position and rotation from the previous linkset and | ||
3039 | // then make them relative to my linkset root. | ||
2992 | private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum) | 3040 | private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum) |
2993 | { | 3041 | { |
2994 | Quaternion parentRot = oldGroupRotation; | 3042 | Quaternion parentRot = oldGroupRotation; |
2995 | Quaternion oldRot = part.RotationOffset; | 3043 | Quaternion oldRot = part.RotationOffset; |
2996 | Quaternion worldRot = parentRot * oldRot; | ||
2997 | |||
2998 | parentRot = oldGroupRotation; | ||
2999 | 3044 | ||
3045 | // Move our position to not be relative to the old parent | ||
3000 | Vector3 axPos = part.OffsetPosition; | 3046 | Vector3 axPos = part.OffsetPosition; |
3001 | |||
3002 | axPos *= parentRot; | 3047 | axPos *= parentRot; |
3003 | part.OffsetPosition = axPos; | 3048 | part.OffsetPosition = axPos; |
3004 | Vector3 newPos = oldGroupPosition + part.OffsetPosition; | 3049 | Vector3 newPos = oldGroupPosition + part.OffsetPosition; |
3005 | part.GroupPosition = newPos; | 3050 | part.GroupPosition = newPos; |
3006 | part.OffsetPosition = Vector3.Zero; | 3051 | part.OffsetPosition = Vector3.Zero; |
3052 | |||
3053 | // Compution our rotation to be not relative to the old parent | ||
3054 | Quaternion worldRot = parentRot * oldRot; | ||
3007 | part.RotationOffset = worldRot; | 3055 | part.RotationOffset = worldRot; |
3008 | 3056 | ||
3057 | // Add this SOP to our linkset | ||
3009 | part.SetParent(this); | 3058 | part.SetParent(this); |
3010 | part.ParentID = m_rootPart.LocalId; | 3059 | part.ParentID = m_rootPart.LocalId; |
3011 | |||
3012 | m_parts.Add(part.UUID, part); | 3060 | m_parts.Add(part.UUID, part); |
3013 | 3061 | ||
3014 | part.LinkNum = linkNum; | 3062 | part.LinkNum = linkNum; |
3015 | 3063 | ||
3016 | part.OffsetPosition = newPos - AbsolutePosition; | 3064 | // Compute the new position of this SOP relative to the group position |
3065 | part.OffsetPosition = part.GroupPosition - AbsolutePosition; | ||
3017 | 3066 | ||
3018 | Quaternion rootRotation = m_rootPart.RotationOffset; | 3067 | // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. |
3068 | // It would have the affect of setting the physics engine position multiple | ||
3069 | // times. In theory, that is not necessary but I don't have a good linkset | ||
3070 | // test to know that cleaning up this code wouldn't break things.) | ||
3019 | 3071 | ||
3072 | // Rotate the relative position by the rotation of the group | ||
3073 | Quaternion rootRotation = m_rootPart.RotationOffset; | ||
3020 | Vector3 pos = part.OffsetPosition; | 3074 | Vector3 pos = part.OffsetPosition; |
3021 | pos *= Quaternion.Conjugate(rootRotation); | 3075 | pos *= Quaternion.Conjugate(rootRotation); |
3022 | part.OffsetPosition = pos; | 3076 | part.OffsetPosition = pos; |
3023 | 3077 | ||
3078 | // Compute the SOP's rotation relative to the rotation of the group. | ||
3024 | parentRot = m_rootPart.RotationOffset; | 3079 | parentRot = m_rootPart.RotationOffset; |
3025 | oldRot = part.RotationOffset; | 3080 | oldRot = part.RotationOffset; |
3026 | Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot; | 3081 | Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot; |
3027 | part.RotationOffset = newRot; | 3082 | part.RotationOffset = newRot; |
3028 | 3083 | ||
3084 | // Since this SOP's state has changed, push those changes into the physics engine | ||
3085 | // and the simulator. | ||
3029 | part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false); | 3086 | part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false); |
3030 | } | 3087 | } |
3031 | 3088 | ||