Many explanitory comments added to the link and delink code in
SOG and SOP. Should have no functionality changes.0.7.4.1
parent
916e3bf886
commit
743437262e
|
@ -451,6 +451,8 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
}
|
||||
}
|
||||
|
||||
// Restuff the new GroupPosition into each SOP of the linkset.
|
||||
// This has the affect of resetting and tainting the physics actors.
|
||||
SceneObjectPart[] parts = m_parts.GetArray();
|
||||
for (int i = 0; i < parts.Length; i++)
|
||||
parts[i].GroupPosition = val;
|
||||
|
@ -1133,6 +1135,9 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
|
||||
public void ResetChildPrimPhysicsPositions()
|
||||
{
|
||||
// Setting this SOG's absolute position also loops through and sets the positions
|
||||
// of the SOP's in this SOG's linkset. This has the side affect of making sure
|
||||
// the physics world matches the simulated world.
|
||||
AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works?
|
||||
|
||||
// teravus: AbsolutePosition is NOT a normal property!
|
||||
|
@ -1987,6 +1992,8 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
LinkToGroup(objectGroup, false);
|
||||
}
|
||||
|
||||
// Link an existing group to this group.
|
||||
// The group being linked need not be a linkset -- it can have just one prim.
|
||||
public void LinkToGroup(SceneObjectGroup objectGroup, bool insert)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
|
@ -1997,35 +2004,51 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
if (objectGroup == this)
|
||||
return;
|
||||
|
||||
// 'linkPart' == the root of the group being linked into this group
|
||||
SceneObjectPart linkPart = objectGroup.m_rootPart;
|
||||
|
||||
// physics flags from group to be applied to linked parts
|
||||
bool grpusephys = UsesPhysics;
|
||||
bool grptemporary = IsTemporary;
|
||||
|
||||
// Remember where the group being linked thought it was
|
||||
Vector3 oldGroupPosition = linkPart.GroupPosition;
|
||||
Quaternion oldRootRotation = linkPart.RotationOffset;
|
||||
|
||||
linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition;
|
||||
linkPart.ParentID = m_rootPart.LocalId;
|
||||
linkPart.GroupPosition = AbsolutePosition;
|
||||
Vector3 axPos = linkPart.OffsetPosition;
|
||||
// A linked SOP remembers its location and rotation relative to the root of a group.
|
||||
// Convert the root of the group being linked to be relative to the
|
||||
// root of the group being linked to.
|
||||
// Note: Some of the assignments have complex side effects.
|
||||
|
||||
// First move the new group's root SOP's position to be relative to ours
|
||||
// (radams1: Not sure if the multiple setting of OffsetPosition is required. If not,
|
||||
// this code can be reordered to have a more logical flow.)
|
||||
linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition;
|
||||
// Assign the new parent to the root of the old group
|
||||
linkPart.ParentID = m_rootPart.LocalId;
|
||||
// Now that it's a child, it's group position is our root position
|
||||
linkPart.GroupPosition = AbsolutePosition;
|
||||
|
||||
Vector3 axPos = linkPart.OffsetPosition;
|
||||
// Rotate the linking root SOP's position to be relative to the new root prim
|
||||
Quaternion parentRot = m_rootPart.RotationOffset;
|
||||
axPos *= Quaternion.Inverse(parentRot);
|
||||
|
||||
linkPart.OffsetPosition = axPos;
|
||||
|
||||
// Make the linking root SOP's rotation relative to the new root prim
|
||||
Quaternion oldRot = linkPart.RotationOffset;
|
||||
Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot;
|
||||
linkPart.RotationOffset = newRot;
|
||||
|
||||
linkPart.ParentID = m_rootPart.LocalId;
|
||||
|
||||
// If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
|
||||
// Now that we know this SOG has at least two SOPs in it, the new root
|
||||
// SOP becomes the first in the linkset.
|
||||
if (m_rootPart.LinkNum == 0)
|
||||
m_rootPart.LinkNum = 1;
|
||||
|
||||
lock (m_parts.SyncRoot)
|
||||
{
|
||||
// Calculate the new link number for the old root SOP
|
||||
int linkNum;
|
||||
if (insert)
|
||||
{
|
||||
|
@ -2041,6 +2064,7 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
linkNum = PrimCount + 1;
|
||||
}
|
||||
|
||||
// Add the old root SOP as a part in our group's list
|
||||
m_parts.Add(linkPart.UUID, linkPart);
|
||||
|
||||
linkPart.SetParent(this);
|
||||
|
@ -2048,6 +2072,8 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
|
||||
// let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
|
||||
linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive);
|
||||
|
||||
// If the added SOP is physical, also tell the physics engine about the link relationship.
|
||||
if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
|
||||
{
|
||||
linkPart.PhysActor.link(m_rootPart.PhysActor);
|
||||
|
@ -2056,20 +2082,26 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
|
||||
linkPart.LinkNum = linkNum++;
|
||||
|
||||
// Get a list of the SOP's in the old group in order of their linknum's.
|
||||
SceneObjectPart[] ogParts = objectGroup.Parts;
|
||||
Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b)
|
||||
{
|
||||
return a.LinkNum - b.LinkNum;
|
||||
});
|
||||
|
||||
// Add each of the SOP's from the old linkset to our linkset
|
||||
for (int i = 0; i < ogParts.Length; i++)
|
||||
{
|
||||
SceneObjectPart part = ogParts[i];
|
||||
if (part.UUID != objectGroup.m_rootPart.UUID)
|
||||
{
|
||||
LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
|
||||
// let physics know
|
||||
|
||||
// Update the physics flags for the newly added SOP
|
||||
// (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
|
||||
part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive);
|
||||
|
||||
// If the added SOP is physical, also tell the physics engine about the link relationship.
|
||||
if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
|
||||
{
|
||||
part.PhysActor.link(m_rootPart.PhysActor);
|
||||
|
@ -2080,6 +2112,7 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
}
|
||||
}
|
||||
|
||||
// Now that we've aquired all of the old SOG's parts, remove the old SOG from the scene.
|
||||
m_scene.UnlinkSceneObject(objectGroup, true);
|
||||
objectGroup.IsDeleted = true;
|
||||
|
||||
|
@ -2152,7 +2185,7 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
/// <remarks>
|
||||
/// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race
|
||||
/// condition. But currently there is no
|
||||
/// alternative method that does take a lonk to delink a single prim.
|
||||
/// alternative method that does take a lock to delink a single prim.
|
||||
/// </remarks>
|
||||
/// <param name="partID"></param>
|
||||
/// <param name="sendEvents"></param>
|
||||
|
@ -2165,6 +2198,7 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
|
||||
linkPart.ClearUndoState();
|
||||
|
||||
Vector3 worldPos = linkPart.GetWorldPosition();
|
||||
Quaternion worldRot = linkPart.GetWorldRotation();
|
||||
|
||||
// Remove the part from this object
|
||||
|
@ -2174,6 +2208,7 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
|
||||
SceneObjectPart[] parts = m_parts.GetArray();
|
||||
|
||||
// Rejigger the linknum's of the remaining SOP's to fill any gap
|
||||
if (parts.Length == 1 && RootPart != null)
|
||||
{
|
||||
// Single prim left
|
||||
|
@ -2195,22 +2230,31 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
|
||||
PhysicsActor linkPartPa = linkPart.PhysActor;
|
||||
|
||||
// Remove the SOP from the physical scene.
|
||||
// If the new SOG is physical, it is re-created later.
|
||||
// (There is a problem here in that we have not yet told the physics
|
||||
// engine about the delink. Someday, linksets should be made first
|
||||
// class objects in the physics engine interface).
|
||||
if (linkPartPa != null)
|
||||
m_scene.PhysicsScene.RemovePrim(linkPartPa);
|
||||
|
||||
// We need to reset the child part's position
|
||||
// ready for life as a separate object after being a part of another object
|
||||
|
||||
/* This commented out code seems to recompute what GetWorldPosition already does.
|
||||
* Replace with a call to GetWorldPosition (before unlinking)
|
||||
Quaternion parentRot = m_rootPart.RotationOffset;
|
||||
|
||||
Vector3 axPos = linkPart.OffsetPosition;
|
||||
|
||||
axPos *= parentRot;
|
||||
linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z);
|
||||
linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition;
|
||||
linkPart.OffsetPosition = new Vector3(0, 0, 0);
|
||||
|
||||
*/
|
||||
linkPart.GroupPosition = worldPos;
|
||||
linkPart.OffsetPosition = Vector3.Zero;
|
||||
linkPart.RotationOffset = worldRot;
|
||||
|
||||
// Create a new SOG to go around this unlinked and unattached SOP
|
||||
SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart);
|
||||
|
||||
m_scene.AddNewSceneObject(objectGroup, true);
|
||||
|
@ -2239,42 +2283,56 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
m_isBackedUp = false;
|
||||
}
|
||||
|
||||
// This links an SOP from a previous linkset into my linkset.
|
||||
// The trick is that the SOP's position and rotation are relative to the old root SOP's
|
||||
// so we are passed in the position and rotation of the old linkset so this can
|
||||
// unjigger this SOP's position and rotation from the previous linkset and
|
||||
// then make them relative to my linkset root.
|
||||
private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum)
|
||||
{
|
||||
Quaternion parentRot = oldGroupRotation;
|
||||
Quaternion oldRot = part.RotationOffset;
|
||||
Quaternion worldRot = parentRot * oldRot;
|
||||
|
||||
parentRot = oldGroupRotation;
|
||||
|
||||
// Move our position to not be relative to the old parent
|
||||
Vector3 axPos = part.OffsetPosition;
|
||||
|
||||
axPos *= parentRot;
|
||||
part.OffsetPosition = axPos;
|
||||
part.GroupPosition = oldGroupPosition + part.OffsetPosition;
|
||||
part.OffsetPosition = Vector3.Zero;
|
||||
|
||||
// Compution our rotation to be not relative to the old parent
|
||||
Quaternion worldRot = parentRot * oldRot;
|
||||
part.RotationOffset = worldRot;
|
||||
|
||||
// Add this SOP to our linkset
|
||||
part.SetParent(this);
|
||||
part.ParentID = m_rootPart.LocalId;
|
||||
|
||||
m_parts.Add(part.UUID, part);
|
||||
|
||||
part.LinkNum = linkNum;
|
||||
|
||||
// Compute the new position of this SOP relative to the group position
|
||||
part.OffsetPosition = part.GroupPosition - AbsolutePosition;
|
||||
|
||||
Quaternion rootRotation = m_rootPart.RotationOffset;
|
||||
// (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
|
||||
// It would have the affect of setting the physics engine position multiple
|
||||
// times. In theory, that is not necessary but I don't have a good linkset
|
||||
// test to know that cleaning up this code wouldn't break things.)
|
||||
|
||||
// Rotate the relative position by the rotation of the group
|
||||
Quaternion rootRotation = m_rootPart.RotationOffset;
|
||||
Vector3 pos = part.OffsetPosition;
|
||||
pos *= Quaternion.Inverse(rootRotation);
|
||||
part.OffsetPosition = pos;
|
||||
|
||||
// Compute the SOP's rotation relative to the rotation of the group.
|
||||
parentRot = m_rootPart.RotationOffset;
|
||||
oldRot = part.RotationOffset;
|
||||
Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot;
|
||||
part.RotationOffset = newRot;
|
||||
|
||||
// Since this SOP's state has changed, push those changes into the physics engine
|
||||
// and the simulator.
|
||||
part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect);
|
||||
}
|
||||
|
||||
|
|
|
@ -693,9 +693,11 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
{
|
||||
// If this is a linkset, we don't want the physics engine mucking up our group position here.
|
||||
PhysicsActor actor = PhysActor;
|
||||
// If physical and the root prim of a linkset, the position of the group is what physics thinks.
|
||||
if (actor != null && ParentID == 0)
|
||||
m_groupPosition = actor.Position;
|
||||
|
||||
// If I'm an attachment, my position is reported as the position of who I'm attached to
|
||||
if (ParentGroup.IsAttachment)
|
||||
{
|
||||
ScenePresence sp = ParentGroup.Scene.GetScenePresence(ParentGroup.AttachedAvatar);
|
||||
|
@ -721,7 +723,7 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
}
|
||||
else
|
||||
{
|
||||
// To move the child prim in respect to the group position and rotation we have to calculate
|
||||
// The physics engine always sees all objects (root or linked) in world coordinates.
|
||||
actor.Position = GetWorldPosition();
|
||||
actor.Orientation = GetWorldRotation();
|
||||
}
|
||||
|
@ -795,6 +797,8 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
{
|
||||
// We don't want the physics engine mucking up the rotations in a linkset
|
||||
PhysicsActor actor = PhysActor;
|
||||
// If this is a root of a linkset, the real rotation is what the physics engine thinks.
|
||||
// If not a root prim, the offset rotation is computed by SOG and is relative to the root.
|
||||
if (ParentID == 0 && (Shape.PCode != 9 || Shape.State == 0) && actor != null)
|
||||
{
|
||||
if (actor.Orientation.X != 0f || actor.Orientation.Y != 0f
|
||||
|
@ -1980,14 +1984,20 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
/// <returns>A Linked Child Prim objects position in world</returns>
|
||||
public Vector3 GetWorldPosition()
|
||||
{
|
||||
Quaternion parentRot = ParentGroup.RootPart.RotationOffset;
|
||||
Vector3 axPos = OffsetPosition;
|
||||
axPos *= parentRot;
|
||||
Vector3 translationOffsetPosition = axPos;
|
||||
Vector3 ret;
|
||||
if (_parentID == 0)
|
||||
return GroupPosition;
|
||||
// if a root SOP, my position is what it is
|
||||
ret = GroupPosition;
|
||||
else
|
||||
return ParentGroup.AbsolutePosition + translationOffsetPosition;
|
||||
{
|
||||
// If a child SOP, my position is relative to the root SOP so take
|
||||
// my info and add the root's position and rotation to
|
||||
// get my world position.
|
||||
Quaternion parentRot = ParentGroup.RootPart.RotationOffset;
|
||||
Vector3 translationOffsetPosition = OffsetPosition * parentRot;
|
||||
ret = ParentGroup.AbsolutePosition + translationOffsetPosition;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -2004,6 +2014,8 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
}
|
||||
else
|
||||
{
|
||||
// A child SOP's rotation is relative to the root SOP's rotation.
|
||||
// Combine them to get my absolute rotation.
|
||||
Quaternion parentRot = ParentGroup.RootPart.RotationOffset;
|
||||
Quaternion oldRot = RotationOffset;
|
||||
newRot = parentRot * oldRot;
|
||||
|
|
Loading…
Reference in New Issue