Merge branch 'master' of ssh://opensimulator.org/var/git/opensim

0.7.4.1
Justin Clark-Casey (justincc) 2012-07-12 22:35:38 +01:00
commit 65a25ee510
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(); SceneObjectPart[] parts = m_parts.GetArray();
for (int i = 0; i < parts.Length; i++) for (int i = 0; i < parts.Length; i++)
parts[i].GroupPosition = val; parts[i].GroupPosition = val;
@ -1133,6 +1135,9 @@ namespace OpenSim.Region.Framework.Scenes
public void ResetChildPrimPhysicsPositions() 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? AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works?
// teravus: AbsolutePosition is NOT a normal property! // teravus: AbsolutePosition is NOT a normal property!
@ -1987,6 +1992,8 @@ namespace OpenSim.Region.Framework.Scenes
LinkToGroup(objectGroup, false); 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) public void LinkToGroup(SceneObjectGroup objectGroup, bool insert)
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
@ -1997,35 +2004,51 @@ namespace OpenSim.Region.Framework.Scenes
if (objectGroup == this) if (objectGroup == this)
return; return;
// 'linkPart' == the root of the group being linked into this group
SceneObjectPart linkPart = objectGroup.m_rootPart; SceneObjectPart linkPart = objectGroup.m_rootPart;
// physics flags from group to be applied to linked parts // physics flags from group to be applied to linked parts
bool grpusephys = UsesPhysics; bool grpusephys = UsesPhysics;
bool grptemporary = IsTemporary; bool grptemporary = IsTemporary;
// Remember where the group being linked thought it was
Vector3 oldGroupPosition = linkPart.GroupPosition; Vector3 oldGroupPosition = linkPart.GroupPosition;
Quaternion oldRootRotation = linkPart.RotationOffset; Quaternion oldRootRotation = linkPart.RotationOffset;
linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; // A linked SOP remembers its location and rotation relative to the root of a group.
linkPart.ParentID = m_rootPart.LocalId; // Convert the root of the group being linked to be relative to the
linkPart.GroupPosition = AbsolutePosition; // root of the group being linked to.
Vector3 axPos = linkPart.OffsetPosition; // 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; Quaternion parentRot = m_rootPart.RotationOffset;
axPos *= Quaternion.Inverse(parentRot); axPos *= Quaternion.Inverse(parentRot);
linkPart.OffsetPosition = axPos; linkPart.OffsetPosition = axPos;
// Make the linking root SOP's rotation relative to the new root prim
Quaternion oldRot = linkPart.RotationOffset; Quaternion oldRot = linkPart.RotationOffset;
Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot;
linkPart.RotationOffset = newRot; 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) if (m_rootPart.LinkNum == 0)
m_rootPart.LinkNum = 1; m_rootPart.LinkNum = 1;
lock (m_parts.SyncRoot) lock (m_parts.SyncRoot)
{ {
// Calculate the new link number for the old root SOP
int linkNum; int linkNum;
if (insert) if (insert)
{ {
@ -2041,6 +2064,7 @@ namespace OpenSim.Region.Framework.Scenes
linkNum = PrimCount + 1; linkNum = PrimCount + 1;
} }
// Add the old root SOP as a part in our group's list
m_parts.Add(linkPart.UUID, linkPart); m_parts.Add(linkPart.UUID, linkPart);
linkPart.SetParent(this); 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 // 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); 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) if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
{ {
linkPart.PhysActor.link(m_rootPart.PhysActor); linkPart.PhysActor.link(m_rootPart.PhysActor);
@ -2056,20 +2082,26 @@ namespace OpenSim.Region.Framework.Scenes
linkPart.LinkNum = linkNum++; linkPart.LinkNum = linkNum++;
// Get a list of the SOP's in the old group in order of their linknum's.
SceneObjectPart[] ogParts = objectGroup.Parts; SceneObjectPart[] ogParts = objectGroup.Parts;
Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b)
{ {
return a.LinkNum - b.LinkNum; 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++) for (int i = 0; i < ogParts.Length; i++)
{ {
SceneObjectPart part = ogParts[i]; SceneObjectPart part = ogParts[i];
if (part.UUID != objectGroup.m_rootPart.UUID) if (part.UUID != objectGroup.m_rootPart.UUID)
{ {
LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); 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); 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) if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
{ {
part.PhysActor.link(m_rootPart.PhysActor); 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); m_scene.UnlinkSceneObject(objectGroup, true);
objectGroup.IsDeleted = true; objectGroup.IsDeleted = true;
@ -2152,7 +2185,7 @@ namespace OpenSim.Region.Framework.Scenes
/// <remarks> /// <remarks>
/// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race
/// condition. But currently there is no /// 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> /// </remarks>
/// <param name="partID"></param> /// <param name="partID"></param>
/// <param name="sendEvents"></param> /// <param name="sendEvents"></param>
@ -2165,6 +2198,7 @@ namespace OpenSim.Region.Framework.Scenes
linkPart.ClearUndoState(); linkPart.ClearUndoState();
Vector3 worldPos = linkPart.GetWorldPosition();
Quaternion worldRot = linkPart.GetWorldRotation(); Quaternion worldRot = linkPart.GetWorldRotation();
// Remove the part from this object // Remove the part from this object
@ -2174,6 +2208,7 @@ namespace OpenSim.Region.Framework.Scenes
SceneObjectPart[] parts = m_parts.GetArray(); SceneObjectPart[] parts = m_parts.GetArray();
// Rejigger the linknum's of the remaining SOP's to fill any gap
if (parts.Length == 1 && RootPart != null) if (parts.Length == 1 && RootPart != null)
{ {
// Single prim left // Single prim left
@ -2195,22 +2230,31 @@ namespace OpenSim.Region.Framework.Scenes
PhysicsActor linkPartPa = linkPart.PhysActor; 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) if (linkPartPa != null)
m_scene.PhysicsScene.RemovePrim(linkPartPa); m_scene.PhysicsScene.RemovePrim(linkPartPa);
// We need to reset the child part's position // We need to reset the child part's position
// ready for life as a separate object after being a part of another object // 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; Quaternion parentRot = m_rootPart.RotationOffset;
Vector3 axPos = linkPart.OffsetPosition; Vector3 axPos = linkPart.OffsetPosition;
axPos *= parentRot; axPos *= parentRot;
linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z);
linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition;
linkPart.OffsetPosition = new Vector3(0, 0, 0); linkPart.OffsetPosition = new Vector3(0, 0, 0);
*/
linkPart.GroupPosition = worldPos;
linkPart.OffsetPosition = Vector3.Zero;
linkPart.RotationOffset = worldRot; linkPart.RotationOffset = worldRot;
// Create a new SOG to go around this unlinked and unattached SOP
SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart);
m_scene.AddNewSceneObject(objectGroup, true); m_scene.AddNewSceneObject(objectGroup, true);
@ -2239,42 +2283,56 @@ namespace OpenSim.Region.Framework.Scenes
m_isBackedUp = false; 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) private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum)
{ {
Quaternion parentRot = oldGroupRotation; Quaternion parentRot = oldGroupRotation;
Quaternion oldRot = part.RotationOffset; 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; Vector3 axPos = part.OffsetPosition;
axPos *= parentRot; axPos *= parentRot;
part.OffsetPosition = axPos; part.OffsetPosition = axPos;
part.GroupPosition = oldGroupPosition + part.OffsetPosition; part.GroupPosition = oldGroupPosition + part.OffsetPosition;
part.OffsetPosition = Vector3.Zero; part.OffsetPosition = Vector3.Zero;
// Compution our rotation to be not relative to the old parent
Quaternion worldRot = parentRot * oldRot;
part.RotationOffset = worldRot; part.RotationOffset = worldRot;
// Add this SOP to our linkset
part.SetParent(this); part.SetParent(this);
part.ParentID = m_rootPart.LocalId; part.ParentID = m_rootPart.LocalId;
m_parts.Add(part.UUID, part); m_parts.Add(part.UUID, part);
part.LinkNum = linkNum; part.LinkNum = linkNum;
// Compute the new position of this SOP relative to the group position
part.OffsetPosition = part.GroupPosition - AbsolutePosition; 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; Vector3 pos = part.OffsetPosition;
pos *= Quaternion.Inverse(rootRotation); pos *= Quaternion.Inverse(rootRotation);
part.OffsetPosition = pos; part.OffsetPosition = pos;
// Compute the SOP's rotation relative to the rotation of the group.
parentRot = m_rootPart.RotationOffset; parentRot = m_rootPart.RotationOffset;
oldRot = part.RotationOffset; oldRot = part.RotationOffset;
Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot;
part.RotationOffset = newRot; 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); 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. // If this is a linkset, we don't want the physics engine mucking up our group position here.
PhysicsActor actor = PhysActor; 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) if (actor != null && ParentID == 0)
m_groupPosition = actor.Position; 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) if (ParentGroup.IsAttachment)
{ {
ScenePresence sp = ParentGroup.Scene.GetScenePresence(ParentGroup.AttachedAvatar); ScenePresence sp = ParentGroup.Scene.GetScenePresence(ParentGroup.AttachedAvatar);
@ -721,7 +723,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
else 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.Position = GetWorldPosition();
actor.Orientation = GetWorldRotation(); 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 // We don't want the physics engine mucking up the rotations in a linkset
PhysicsActor actor = PhysActor; 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 (ParentID == 0 && (Shape.PCode != 9 || Shape.State == 0) && actor != null)
{ {
if (actor.Orientation.X != 0f || actor.Orientation.Y != 0f 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> /// <returns>A Linked Child Prim objects position in world</returns>
public Vector3 GetWorldPosition() public Vector3 GetWorldPosition()
{ {
Quaternion parentRot = ParentGroup.RootPart.RotationOffset; Vector3 ret;
Vector3 axPos = OffsetPosition; if (_parentID == 0)
axPos *= parentRot; // if a root SOP, my position is what it is
Vector3 translationOffsetPosition = axPos; ret = GroupPosition;
if(_parentID == 0)
return GroupPosition;
else 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> /// <summary>
@ -2004,6 +2014,8 @@ namespace OpenSim.Region.Framework.Scenes
} }
else 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 parentRot = ParentGroup.RootPart.RotationOffset;
Quaternion oldRot = RotationOffset; Quaternion oldRot = RotationOffset;
newRot = parentRot * oldRot; newRot = parentRot * oldRot;