Many explanitory comments added to the link and delink code in

SOG and SOP. Should have no functionality changes.
0.7.4.1
Robert Adams 2012-07-11 16:07:14 -07:00
parent 916e3bf886
commit 743437262e
2 changed files with 96 additions and 26 deletions

View File

@ -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);
}

View File

@ -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;
if(_parentID == 0)
return GroupPosition;
Vector3 ret;
if (_parentID == 0)
// 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;