aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs')
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs91
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