/// <summary> /// Send new AgentUpdate packet to update our current camera /// position and rotation /// </summary> /// <param name="reliable">Whether to require server acknowledgement /// of this packet</param> /// <param name="simulator">Simulator to send the update to</param> public void SendUpdate(bool reliable, Simulator simulator) { Vector3f origin = Camera.Position; Vector3f xAxis = Camera.LeftAxis; Vector3f yAxis = Camera.AtAxis; Vector3f zAxis = Camera.UpAxis; // Attempted to sort these in a rough order of how often they might change if (agentControls == 0 && yAxis == LastCameraYAxis && origin == LastCameraCenter && State == lastState && HeadRotation == LastHeadRotation && BodyRotation == LastBodyRotation && xAxis == LastCameraXAxis && Camera.Far == LastFar && zAxis == LastCameraZAxis) { ++duplicateCount; } else { duplicateCount = 0; } if (Client.Settings.DISABLE_AGENT_UPDATE_DUPLICATE_CHECK || duplicateCount < 10) { // Store the current state to do duplicate checking LastHeadRotation = HeadRotation; LastBodyRotation = BodyRotation; LastCameraYAxis = yAxis; LastCameraCenter = origin; LastCameraXAxis = xAxis; LastCameraZAxis = zAxis; LastFar = Camera.Far; lastState = State; // Build the AgentUpdate packet and send it AgentUpdatePacket update = new AgentUpdatePacket(); update.Header.Reliable = reliable; update.AgentData.AgentID = Client.Self.AgentID; update.AgentData.SessionID = Client.Self.SessionID; update.AgentData.HeadRotation = HeadRotation; update.AgentData.BodyRotation = BodyRotation; update.AgentData.CameraAtAxis = yAxis; update.AgentData.CameraCenter = origin; update.AgentData.CameraLeftAxis = xAxis; update.AgentData.CameraUpAxis = zAxis; update.AgentData.Far = Camera.Far; update.AgentData.State = (byte)State; update.AgentData.ControlFlags = agentControls; update.AgentData.Flags = (byte)Flags; Client.Network.SendPacket(update, simulator); if (autoResetControls) { ResetControlFlags(); } } }
/// <summary> /// Builds an AgentUpdate packet entirely from parameters. This /// will not touch the state of Self.Movement or /// Self.Movement.Camera in any way /// </summary> /// <param name="controlFlags"></param> /// <param name="position"></param> /// <param name="forwardAxis"></param> /// <param name="leftAxis"></param> /// <param name="upAxis"></param> /// <param name="bodyRotation"></param> /// <param name="headRotation"></param> /// <param name="farClip"></param> /// <param name="reliable"></param> /// <param name="flags"></param> /// <param name="state"></param> public void SendManualUpdate(AgentManager.ControlFlags controlFlags, Vector3f position, Vector3f forwardAxis, Vector3f leftAxis, Vector3f upAxis, Quaternionf bodyRotation, Quaternionf headRotation, float farClip, AgentFlags flags, AgentState state, bool reliable) { AgentUpdatePacket update = new AgentUpdatePacket(); update.AgentData.AgentID = Client.Self.AgentID; update.AgentData.SessionID = Client.Self.SessionID; update.AgentData.BodyRotation = bodyRotation; update.AgentData.HeadRotation = headRotation; update.AgentData.CameraCenter = position; update.AgentData.CameraAtAxis = forwardAxis; update.AgentData.CameraLeftAxis = leftAxis; update.AgentData.CameraUpAxis = upAxis; update.AgentData.Far = farClip; update.AgentData.ControlFlags = (uint)controlFlags; update.AgentData.Flags = (byte)flags; update.AgentData.State = (byte)state; update.Header.Reliable = reliable; Client.Network.SendPacket(update); }
/// <summary> /// Rez an object from inventory /// </summary> /// <param name="simulator">Simulator to place object in</param> /// <param name="rotation">Rotation of the object when rezzed</param> /// <param name="position">Vector of where to place object</param> /// <param name="item">InventoryObject object containing item details</param> /// <param name="groupOwner">Guid of group to own the object</param> public Guid RequestRezFromInventory(Simulator simulator, Quaternionf rotation, Vector3f position, InventoryObject item, Guid groupOwner) { return RequestRezFromInventory(simulator, rotation, position, item, groupOwner, Guid.NewGuid(), false); }
/// <summary> /// Used for new prims, or significant changes to existing prims /// </summary> /// <param name="packet"></param> /// <param name="simulator"></param> protected void UpdateHandler(Packet packet, Simulator simulator) { ObjectUpdatePacket update = (ObjectUpdatePacket)packet; UpdateDilation(simulator, update.RegionData.TimeDilation); for (int b = 0; b < update.ObjectData.Length; b++) { ObjectUpdatePacket.ObjectDataBlock block = update.ObjectData[b]; Vector4f collisionPlane = Vector4f.Zero; Vector3f position = Vector3f.Zero; Vector3f velocity = Vector3f.Zero; Vector3f acceleration = Vector3f.Zero; Quaternionf rotation = Quaternionf.Identity; Vector3f angularVelocity = Vector3f.Zero; NameValue[] nameValues; bool attachment = false; PCode pcode = (PCode)block.PCode; #region Relevance check // Check if we are interested in this object if (!Client.Settings.ALWAYS_DECODE_OBJECTS) { switch (pcode) { case PCode.Grass: case PCode.Tree: case PCode.NewTree: if (OnNewFoliage == null) continue; break; case PCode.Prim: if (OnNewPrim == null) continue; break; case PCode.Avatar: // Make an exception for updates about our own agent if (block.FullID != Client.Self.AgentID && OnNewAvatar == null) continue; break; case PCode.ParticleSystem: continue; // TODO: Do something with these } } #endregion Relevance check #region NameValue parsing string nameValue = Utils.BytesToString(block.NameValue); if (nameValue.Length > 0) { string[] lines = nameValue.Split('\n'); nameValues = new NameValue[lines.Length]; for (int i = 0; i < lines.Length; i++) { if (!String.IsNullOrEmpty(lines[i])) { NameValue nv = new NameValue(lines[i]); if (nv.Name == "AttachItemID") attachment = true; nameValues[i] = nv; } } } else { nameValues = new NameValue[0]; } #endregion NameValue parsing #region Decode Object (primitive) parameters Primitive.ConstructionData data = new Primitive.ConstructionData(); data.State = block.State; data.Material = (Material)block.Material; data.PathCurve = (PathCurve)block.PathCurve; data.profileCurve = block.ProfileCurve; data.PathBegin = Primitive.UnpackBeginCut(block.PathBegin); data.PathEnd = Primitive.UnpackEndCut(block.PathEnd); data.PathScaleX = Primitive.UnpackPathScale(block.PathScaleX); data.PathScaleY = Primitive.UnpackPathScale(block.PathScaleY); data.PathShearX = Primitive.UnpackPathShear((sbyte)block.PathShearX); data.PathShearY = Primitive.UnpackPathShear((sbyte)block.PathShearY); data.PathTwist = Primitive.UnpackPathTwist(block.PathTwist); data.PathTwistBegin = Primitive.UnpackPathTwist(block.PathTwistBegin); data.PathRadiusOffset = Primitive.UnpackPathTwist(block.PathRadiusOffset); data.PathTaperX = Primitive.UnpackPathTaper(block.PathTaperX); data.PathTaperY = Primitive.UnpackPathTaper(block.PathTaperY); data.PathRevolutions = Primitive.UnpackPathRevolutions(block.PathRevolutions); data.PathSkew = Primitive.UnpackPathTwist(block.PathSkew); data.ProfileBegin = Primitive.UnpackBeginCut(block.ProfileBegin); data.ProfileEnd = Primitive.UnpackEndCut(block.ProfileEnd); data.ProfileHollow = Primitive.UnpackProfileHollow(block.ProfileHollow); data.PCode = pcode; #endregion #region Decode Additional packed parameters in ObjectData int pos = 0; switch (block.ObjectData.Length) { case 76: // Collision normal for avatar collisionPlane.FromBytes(block.ObjectData, pos); pos += 16; goto case 60; case 60: // Position position.FromBytes(block.ObjectData, pos); pos += 12; // Velocity velocity.FromBytes(block.ObjectData, pos); pos += 12; // Acceleration acceleration.FromBytes(block.ObjectData, pos); pos += 12; // Rotation (theta) rotation.FromBytes(block.ObjectData, pos, true); pos += 12; // Angular velocity (omega) angularVelocity.FromBytes(block.ObjectData, pos); pos += 12; break; case 48: // Collision normal for avatar collisionPlane.FromBytes(block.ObjectData, pos); pos += 16; goto case 32; case 32: // The data is an array of unsigned shorts // Position position = new Vector3f( Utils.UInt16ToFloat(block.ObjectData, pos, -0.5f * 256.0f, 1.5f * 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 2, -0.5f * 256.0f, 1.5f * 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 3.0f * 256.0f)); pos += 6; // Velocity velocity = new Vector3f( Utils.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f)); pos += 6; // Acceleration acceleration = new Vector3f( Utils.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f)); pos += 6; // Rotation (theta) rotation = new Quaternionf( Utils.UInt16ToFloat(block.ObjectData, pos, -1.0f, 1.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 2, -1.0f, 1.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 4, -1.0f, 1.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 6, -1.0f, 1.0f)); pos += 8; // Angular velocity (omega) angularVelocity = new Vector3f( Utils.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f)); pos += 6; break; case 16: // The data is an array of single bytes (8-bit numbers) // Position position = new Vector3f( Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); pos += 3; // Velocity velocity = new Vector3f( Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); pos += 3; // Accleration acceleration = new Vector3f( Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); pos += 3; // Rotation rotation = new Quaternionf( Utils.ByteToFloat(block.ObjectData, pos, -1.0f, 1.0f), Utils.ByteToFloat(block.ObjectData, pos + 1, -1.0f, 1.0f), Utils.ByteToFloat(block.ObjectData, pos + 2, -1.0f, 1.0f), Utils.ByteToFloat(block.ObjectData, pos + 3, -1.0f, 1.0f)); pos += 4; // Angular Velocity angularVelocity = new Vector3f( Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); pos += 3; break; default: Logger.Log("Got an ObjectUpdate block with ObjectUpdate field length of " + block.ObjectData.Length, Helpers.LogLevel.Warning, Client); continue; } #endregion // Determine the object type and create the appropriate class switch (pcode) { #region Prim and Foliage case PCode.Grass: case PCode.Tree: case PCode.NewTree: case PCode.Prim: Primitive prim = GetPrimitive(simulator, block.ID, block.FullID); #region Update Prim Info with decoded data prim.Flags = (PrimFlags)block.UpdateFlags; if ((prim.Flags & PrimFlags.ZlibCompressed) != 0) { Logger.Log("Got a ZlibCompressed ObjectUpdate, implement me!", Helpers.LogLevel.Warning, Client); continue; } // Automatically request ObjectProperties for prim if it was rezzed selected. if ((prim.Flags & PrimFlags.CreateSelected) != 0) { SelectObject(simulator, prim.LocalID); } prim.NameValues = nameValues; prim.LocalID = block.ID; prim.ID = block.FullID; prim.ParentID = block.ParentID; prim.RegionHandle = update.RegionData.RegionHandle; prim.Scale = block.Scale; prim.ClickAction = (ClickAction)block.ClickAction; prim.OwnerID = block.OwnerID; prim.MediaURL = Utils.BytesToString(block.MediaURL); prim.Text = Utils.BytesToString(block.Text); prim.TextColor = new Color4(block.TextColor, 0, false, true); // Sound information prim.Sound = block.Sound; prim.SoundFlags = block.Flags; prim.SoundGain = block.Gain; prim.SoundRadius = block.Radius; // Joint information prim.Joint = (JointType)block.JointType; prim.JointPivot = block.JointPivot; prim.JointAxisOrAnchor = block.JointAxisOrAnchor; // Object parameters prim.PrimData = data; // Textures, texture animations, particle system, and extra params prim.Textures = new Primitive.TextureEntry(block.TextureEntry, 0, block.TextureEntry.Length); prim.TextureAnim = new Primitive.TextureAnimation(block.TextureAnim, 0); prim.ParticleSys = new Primitive.ParticleSystem(block.PSBlock, 0); prim.SetExtraParamsFromBytes(block.ExtraParams, 0); // PCode-specific data prim.GenericData = block.Data; // Packed parameters prim.CollisionPlane = collisionPlane; prim.Position = position; prim.Velocity = velocity; prim.Acceleration = acceleration; prim.Rotation = rotation; prim.AngularVelocity = angularVelocity; #endregion if (attachment) FireOnNewAttachment(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); else if (pcode == PCode.Prim) FireOnNewPrim(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); else FireOnNewFoliage(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); break; #endregion Prim and Foliage #region Avatar case PCode.Avatar: // Update some internals if this is our avatar if (block.FullID == Client.Self.AgentID) { #region Update Client.Self // We need the local ID to recognize terse updates for our agent Client.Self.localID = block.ID; // Packed parameters Client.Self.collisionPlane = collisionPlane; Client.Self.relativePosition = position; Client.Self.velocity = velocity; Client.Self.acceleration = acceleration; Client.Self.relativeRotation = rotation; Client.Self.angularVelocity = angularVelocity; #endregion } #region Create an Avatar from the decoded data Avatar avatar = GetAvatar(simulator, block.ID, block.FullID); uint oldSeatID = avatar.ParentID; avatar.ID = block.FullID; avatar.LocalID = block.ID; avatar.CollisionPlane = collisionPlane; avatar.Position = position; avatar.Velocity = velocity; avatar.Acceleration = acceleration; avatar.Rotation = rotation; avatar.AngularVelocity = angularVelocity; avatar.NameValues = nameValues; avatar.PrimData = data; avatar.GenericData = block.Data; avatar.ParentID = block.ParentID; SetAvatarSittingOn(simulator, avatar, block.ParentID, oldSeatID); // Textures avatar.Textures = new Primitive.TextureEntry(block.TextureEntry, 0, block.TextureEntry.Length); #endregion Create an Avatar from the decoded data FireOnNewAvatar(simulator, avatar, update.RegionData.RegionHandle, update.RegionData.TimeDilation); break; #endregion Avatar case PCode.ParticleSystem: DecodeParticleUpdate(block); // TODO: Create a callback for particle updates break; default: Logger.DebugLog("Got an ObjectUpdate block with an unrecognized PCode " + pcode.ToString(), Client); break; } } }
public void Rotate(float angle, Vector3f rotationAxis) { Quaternionf q = new Quaternionf(); q.FromAxisAngle(rotationAxis, angle); Rotate(q); }
public void Yaw(float angle) { Quaternionf q = new Quaternionf(); q.FromAxisAngle(zAxis, angle); Matrix4f m = new Matrix4f(); m.FromQuaternion(q); Rotate(m); if (!xAxis.IsFinite() || !yAxis.IsFinite()) throw new Exception("Non-finite in CoordinateFrame.Yaw()"); }
public float Dot(Quaternionf quaternion) { return (Vector.X * quaternion.Vector.X) + (Vector.Y * quaternion.Vector.Y) + (Vector.Z * quaternion.Vector.Z) + (Vector.W * quaternion.Vector.W); }
public void FromQuaternion(Quaternionf quaternion) { Matrix4f m1 = new Matrix4f( quaternion.W, quaternion.Z, -quaternion.Y, quaternion.X, -quaternion.Z, quaternion.W, quaternion.X, quaternion.Y, quaternion.Y, -quaternion.X, quaternion.W, quaternion.Z, -quaternion.X, -quaternion.Y, -quaternion.Z, quaternion.W); Matrix4f m2 = new Matrix4f( quaternion.W, quaternion.Z, -quaternion.Y, -quaternion.X, -quaternion.Z, quaternion.W, quaternion.X, -quaternion.Y, quaternion.Y, -quaternion.X, quaternion.W, -quaternion.Z, quaternion.X, quaternion.Y, quaternion.Z, quaternion.W); this = m1 * m2; }
/// <summary> /// Change the rotation of an object /// </summary> /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param> /// <param name="localID">The objects ID which is local to the simulator the object is in</param> /// <param name="rotation">The new rotation of the object</param> public void SetRotation(Simulator simulator, uint localID, Quaternionf rotation) { ObjectRotationPacket objRotPacket = new ObjectRotationPacket(); objRotPacket.AgentData.AgentID = Client.Self.AgentID; objRotPacket.AgentData.SessionID = Client.Self.SessionID; objRotPacket.ObjectData = new ObjectRotationPacket.ObjectDataBlock[1]; objRotPacket.ObjectData[0] = new ObjectRotationPacket.ObjectDataBlock(); objRotPacket.ObjectData[0].ObjectLocalID = localID; objRotPacket.ObjectData[0].Rotation = rotation; Client.Network.SendPacket(objRotPacket, simulator); }
/// <summary> /// Attach an object to this avatar /// </summary> /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param> /// <param name="localID">The objects ID which is local to the simulator the object is in</param> /// <param name="attachPoint">The point on the avatar the object will be attached</param> /// <param name="rotation">The rotation of the attached object</param> public void AttachObject(Simulator simulator, uint localID, AttachmentPoint attachPoint, Quaternionf rotation) { ObjectAttachPacket attach = new ObjectAttachPacket(); attach.AgentData.AgentID = Client.Self.AgentID; attach.AgentData.SessionID = Client.Self.SessionID; attach.AgentData.AttachmentPoint = (byte)attachPoint; attach.ObjectData = new ObjectAttachPacket.ObjectDataBlock[1]; attach.ObjectData[0] = new ObjectAttachPacket.ObjectDataBlock(); attach.ObjectData[0].ObjectLocalID = localID; attach.ObjectData[0].Rotation = rotation; Client.Network.SendPacket(attach, simulator); }
/// <summary> /// Rez grass and ground cover /// </summary> /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param> /// <param name="scale">The size of the grass</param> /// <param name="rotation">The rotation of the grass</param> /// <param name="position">The position of the grass</param> /// <param name="grassType">The type of grass from the <seealso cref="Grass"/> enum</param> /// <param name="groupOwner">The <seealso cref="Guid"/> of the group to set the tree to, /// or Guid.Empty if no group is to be set</param> public void AddGrass(Simulator simulator, Vector3f scale, Quaternionf rotation, Vector3f position, Grass grassType, Guid groupOwner) { ObjectAddPacket add = new ObjectAddPacket(); add.AgentData.AgentID = Client.Self.AgentID; add.AgentData.SessionID = Client.Self.SessionID; add.AgentData.GroupID = groupOwner; add.ObjectData.BypassRaycast = 1; add.ObjectData.Material = 3; add.ObjectData.PathCurve = 16; add.ObjectData.PCode = (byte)PCode.Grass; add.ObjectData.RayEnd = position; add.ObjectData.RayStart = position; add.ObjectData.RayTargetID = Guid.Empty; add.ObjectData.Rotation = rotation; add.ObjectData.Scale = scale; add.ObjectData.State = (byte)grassType; Client.Network.SendPacket(add, simulator); }
/// <summary> /// Create, or "rez" a new prim object in a simulator /// </summary> /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object to place the object in</param> /// <param name="prim">Data describing the prim object to rez</param> /// <param name="groupID">Group ID that this prim will be set to, or Guid.Empty if you /// do not want the object to be associated with a specific group</param> /// <param name="position">An approximation of the position at which to rez the prim</param> /// <param name="scale">Scale vector to size this prim</param> /// <param name="rotation">Rotation quaternion to rotate this prim</param> /// <remarks>Due to the way client prim rezzing is done on the server, /// the requested position for an object is only close to where the prim /// actually ends up. If you desire exact placement you'll need to /// follow up by moving the object after it has been created. This /// function will not set textures, light and flexible data, or other /// extended primitive properties</remarks> public void AddPrim(Simulator simulator, Primitive.ConstructionData prim, Guid groupID, Vector3f position, Vector3f scale, Quaternionf rotation) { ObjectAddPacket packet = new ObjectAddPacket(); packet.AgentData.AgentID = Client.Self.AgentID; packet.AgentData.SessionID = Client.Self.SessionID; packet.AgentData.GroupID = groupID; packet.ObjectData.State = prim.State; packet.ObjectData.AddFlags = (uint)PrimFlags.CreateSelected; packet.ObjectData.PCode = (byte)PCode.Prim; packet.ObjectData.Material = (byte)prim.Material; packet.ObjectData.Scale = scale; packet.ObjectData.Rotation = rotation; packet.ObjectData.PathCurve = (byte)prim.PathCurve; packet.ObjectData.PathBegin = Primitive.PackBeginCut(prim.PathBegin); packet.ObjectData.PathEnd = Primitive.PackEndCut(prim.PathEnd); packet.ObjectData.PathRadiusOffset = Primitive.PackPathTwist(prim.PathRadiusOffset); packet.ObjectData.PathRevolutions = Primitive.PackPathRevolutions(prim.PathRevolutions); packet.ObjectData.PathScaleX = Primitive.PackPathScale(prim.PathScaleX); packet.ObjectData.PathScaleY = Primitive.PackPathScale(prim.PathScaleY); packet.ObjectData.PathShearX = (byte)Primitive.PackPathShear(prim.PathShearX); packet.ObjectData.PathShearY = (byte)Primitive.PackPathShear(prim.PathShearY); packet.ObjectData.PathSkew = Primitive.PackPathTwist(prim.PathSkew); packet.ObjectData.PathTaperX = Primitive.PackPathTaper(prim.PathTaperX); packet.ObjectData.PathTaperY = Primitive.PackPathTaper(prim.PathTaperY); packet.ObjectData.PathTwist = Primitive.PackPathTwist(prim.PathTwist); packet.ObjectData.PathTwistBegin = Primitive.PackPathTwist(prim.PathTwistBegin); packet.ObjectData.ProfileCurve = prim.profileCurve; packet.ObjectData.ProfileBegin = Primitive.PackBeginCut(prim.ProfileBegin); packet.ObjectData.ProfileEnd = Primitive.PackEndCut(prim.ProfileEnd); packet.ObjectData.ProfileHollow = Primitive.PackProfileHollow(prim.ProfileHollow); packet.ObjectData.RayStart = position; packet.ObjectData.RayEnd = position; packet.ObjectData.RayEndIsIntersection = 0; packet.ObjectData.RayTargetID = Guid.Empty; packet.ObjectData.BypassRaycast = 1; Client.Network.SendPacket(packet, simulator); }
protected void InterpolationTimer_Elapsed(object obj) { if (Client.Network.Connected) { int interval = Environment.TickCount - Client.Self.lastInterpolation; float seconds = (float)interval / 1000f; // Iterate through all of the simulators lock (Client.Network.Simulators) { for (int i = 0; i < Client.Network.Simulators.Count; i++) { float adjSeconds = seconds * Client.Network.Simulators[i].Stats.Dilation; // Iterate through all of this sims avatars Client.Network.Simulators[i].ObjectsAvatars.ForEach( delegate(Avatar avatar) { #region Linear Motion // Only do movement interpolation (extrapolation) when there is a non-zero velocity but // no acceleration if (avatar.Acceleration != Vector3f.Zero && avatar.Velocity == Vector3f.Zero) { avatar.Position += (avatar.Velocity + avatar.Acceleration * (0.5f * (adjSeconds - HAVOK_TIMESTEP))) * adjSeconds; avatar.Velocity += avatar.Acceleration * adjSeconds; } #endregion Linear Motion } ); // Iterate through all of this sims primitives Client.Network.Simulators[i].ObjectsPrimitives.ForEach( delegate(Primitive prim) { if (prim.Joint == JointType.Invalid) { #region Angular Velocity Vector3f angVel = prim.AngularVelocity; float omega = angVel.LengthSquared(); if (omega > 0.00001f) { omega = (float)Math.Sqrt(omega); float angle = omega * adjSeconds; angVel *= 1.0f / omega; Quaternionf dQ = new Quaternionf(); dQ.FromAxisAngle(angVel, angle); prim.Rotation *= dQ; } #endregion Angular Velocity #region Linear Motion // Only do movement interpolation (extrapolation) when there is a non-zero velocity but // no acceleration if (prim.Acceleration != Vector3f.Zero && prim.Velocity == Vector3f.Zero) { prim.Position += (prim.Velocity + prim.Acceleration * (0.5f * (adjSeconds - HAVOK_TIMESTEP))) * adjSeconds; prim.Velocity += prim.Acceleration * adjSeconds; } #endregion Linear Motion } else if (prim.Joint == JointType.Hinge) { //FIXME: Hinge movement extrapolation } else if (prim.Joint == JointType.Point) { //FIXME: Point movement extrapolation } else { Logger.Log("Unhandled joint type " + prim.Joint, Helpers.LogLevel.Warning, Client); } } ); } } // Make sure the last interpolated time is always updated Client.Self.lastInterpolation = Environment.TickCount; } }
public Quaternionf GetQuaternion() { Quaternionf quat = new Quaternionf(); float trace = Trace() + 1f; if (trace > Single.Epsilon) { float s = 0.5f / (float)System.Math.Sqrt(trace); quat.X = (R2.Y - R1.Z) * s; quat.Y = (R0.Z - R2.X) * s; quat.Z = (R1.X - R0.Y) * s; quat.W = 0.25f / s; } else { if (R0.X > R1.Y && R0.X > R2.Z) { float s = 2.0f * (float)System.Math.Sqrt(1.0f + R0.X - R1.Y - R2.Z); quat.X = 0.25f * s; quat.Y = (R0.Y + R1.X) / s; quat.Z = (R0.Z + R2.X) / s; quat.W = (R1.Z - R2.Y) / s; } else if (R1.Y > R2.Z) { float s = 2.0f * (float)System.Math.Sqrt(1.0f + R1.Y - R0.X - R2.Z); quat.X = (R0.Y + R1.X) / s; quat.Y = 0.25f * s; quat.Z = (R1.Z + R2.Y) / s; quat.W = (R0.Z - R2.X) / s; } else { float s = 2.0f * (float)System.Math.Sqrt(1.0f + R2.Z - R0.X - R1.Y); quat.X = (R0.Z + R2.X) / s; quat.Y = (R1.Z + R2.Y) / s; quat.Z = 0.25f * s; quat.W = (R0.Y - R1.X) / s; } } return quat; }
/// <summary> /// Spherical linear interpolation between this quaternion and another /// </summary> /// <param name="quaternion"></param> /// <param name="amount"></param> public Quaternionf Slerp(Quaternionf quaternion, float amount) { float angle = Dot(quaternion); Quaternionf q1 = this; if (angle < 0f) { q1.Negate(); angle *= -1f; } float scale; float invscale; if ((angle + 1f) > 0.05f) { if ((1f - angle) >= 0.05f) { // slerp float theta = (float)System.Math.Acos(angle); float invsintheta = 1f / (float)System.Math.Sin(theta); scale = (float)System.Math.Sin(theta * (1f - amount)) * invsintheta; invscale = (float)System.Math.Sin(theta * amount) * invsintheta; } else { // lerp scale = 1f - amount; invscale = amount; } } else { quaternion.X = -q1.Y; quaternion.Y = q1.X; quaternion.Z = -q1.W; quaternion.W = q1.Z; scale = (float)System.Math.Sin(Utils.Pi * (0.5f - amount)); invscale = (float)System.Math.Sin(Utils.Pi * amount); } return (q1 * scale) + (quaternion * invscale); }
public Matrix4f Transform(Quaternionf rotation) { float x2 = rotation.X + rotation.X; float y2 = rotation.Y + rotation.Y; float z2 = rotation.Z + rotation.Z; float a = (1f - rotation.Y * y2) - rotation.Z * z2; float b = rotation.X * y2 - rotation.W * z2; float c = rotation.X * z2 + rotation.W * y2; float d = rotation.X * y2 + rotation.W * z2; float e = (1f - rotation.X * x2) - rotation.Z * z2; float f = rotation.Y * z2 - rotation.W * x2; float g = rotation.X * z2 - rotation.W * y2; float h = rotation.Y * z2 + rotation.W * x2; float i = (1f - rotation.X * x2) - rotation.Y * y2; return new Matrix4f( new Vector4f( ((R0.X * a) + (R0.Y * b)) + (R0.Z * c), ((R0.X * d) + (R0.Y * e)) + (R0.Z * f), ((R0.X * g) + (R0.Y * h)) + (R0.Z * i), R0.W), new Vector4f( ((R1.X * a) + (R1.Y * b)) + (R1.Z * c), ((R1.X * d) + (R1.Y * e)) + (R1.Z * f), ((R1.X * g) + (R1.Y * h)) + (R1.Z * i), R1.W), new Vector4f( ((R2.X * a) + (R2.Y * b)) + (R2.Z * c), ((R2.X * d) + (R2.Y * e)) + (R2.Z * f), ((R2.X * g) + (R2.Y * h)) + (R2.Z * i), R2.W), new Vector4f( ((R3.X * a) + (R3.Y * b)) + (R3.Z * c), ((R3.X * d) + (R3.Y * e)) + (R3.Z * f), ((R3.X * g) + (R3.Y * h)) + (R3.Z * i), R3.W)); }
public bool ApproxEquals(Quaternionf quaternion, float tolerance) { Vector4f diff = Vector - quaternion.Vector; return (diff.Length() <= tolerance); }
public CoordinateFrame(Vector3f origin, Quaternionf rotation) { Matrix4f m = new Matrix4f(); m.FromQuaternion(rotation); this.origin = origin; xAxis = new Vector3f(m.M11, m.M21, m.M31); yAxis = new Vector3f(m.M12, m.M22, m.M32); zAxis = new Vector3f(m.M13, m.M23, m.M33); if (!IsFinite()) throw new ArgumentException("Non-finite in CoordinateFrame constructor"); }
public Quaternionf(Quaternionf quaternion) { Vector = quaternion.Vector; }
public void Rotate(Quaternionf q) { Matrix4f m = new Matrix4f(); m.FromQuaternion(q); Rotate(m); }
/// <summary> /// Send an AgentUpdate with the camera set at the current agent /// position and pointing towards the heading specified /// </summary> /// <param name="heading">Camera rotation in radians</param> /// <param name="reliable">Whether to send the AgentUpdate reliable /// or not</param> public void UpdateFromHeading(double heading, bool reliable) { Camera.Position = Client.Self.SimPosition; Camera.LookDirection(heading); BodyRotation.Z = (float)Math.Sin(heading / 2.0d); BodyRotation.W = (float)Math.Cos(heading / 2.0d); HeadRotation = BodyRotation; SendUpdate(reliable); }
/// <summary> /// Rez an object from inventory /// </summary> /// <param name="simulator">Simulator to place object in</param> /// <param name="rotation">Rotation of the object when rezzed</param> /// <param name="position">Vector of where to place object</param> /// <param name="item">InventoryObject object containing item details</param> public Guid RequestRezFromInventory(Simulator simulator, Quaternionf rotation, Vector3f position, InventoryObject item) { return RequestRezFromInventory(simulator, rotation, position, item, _Client.Self.ActiveGroup, Guid.NewGuid(), false); }
/// <summary> /// Rotates the avatar body and camera toward a target position. /// This will also anchor the camera position on the avatar /// </summary> /// <param name="target">Region coordinates to turn toward</param> public bool TurnToward(Vector3f target) { if (Client.Settings.SEND_AGENT_UPDATES) { Quaternionf parentRot = Quaternionf.Identity; if (Client.Self.SittingOn > 0) { if (!Client.Network.CurrentSim.ObjectsPrimitives.ContainsKey(Client.Self.SittingOn)) { Logger.Log("Attempted TurnToward but parent prim is not in dictionary", Helpers.LogLevel.Warning, Client); return false; } else parentRot = Client.Network.CurrentSim.ObjectsPrimitives[Client.Self.SittingOn].Rotation; } Vector3f norm = target - Client.Self.SimPosition; norm.Normalize(); Quaternionf rotBetween = Vector3f.UnitX.RotationBetween(ref norm); Quaternionf rot = rotBetween * (Quaternionf.Identity / parentRot); BodyRotation = rot; HeadRotation = rot; Camera.LookAt(Client.Self.SimPosition, target); SendUpdate(); return true; } else { Logger.Log("Attempted TurnToward but agent updates are disabled", Helpers.LogLevel.Warning, Client); return false; } }
/// <summary> /// Rez an object from inventory /// </summary> /// <param name="simulator">Simulator to place object in</param> /// <param name="rotation">Rotation of the object when rezzed</param> /// <param name="position">Vector of where to place object</param> /// <param name="item">InventoryObject object containing item details</param> /// <param name="groupOwner">Guid of group to own the object</param> /// <param name="queryID">User defined queryID to correlate replies</param> /// <param name="requestObjectDetails">if set to true the simulator /// will automatically send object detail packet(s) back to the client</param> public Guid RequestRezFromInventory(Simulator simulator, Quaternionf rotation, Vector3f position, InventoryObject item, Guid groupOwner, Guid queryID, bool requestObjectDetails) { RezObjectPacket add = new RezObjectPacket(); add.AgentData.AgentID = _Client.Self.AgentID; add.AgentData.SessionID = _Client.Self.SessionID; add.AgentData.GroupID = groupOwner; add.RezData.FromTaskID = Guid.Empty; add.RezData.BypassRaycast = 1; add.RezData.RayStart = position; add.RezData.RayEnd = position; add.RezData.RayTargetID = Guid.Empty; add.RezData.RayEndIsIntersection = false; add.RezData.RezSelected = requestObjectDetails; add.RezData.RemoveItem = false; add.RezData.ItemFlags = (uint)item.Flags; add.RezData.GroupMask = (uint)item.Permissions.GroupMask; add.RezData.EveryoneMask = (uint)item.Permissions.EveryoneMask; add.RezData.NextOwnerMask = (uint)item.Permissions.NextOwnerMask; add.InventoryData.ItemID = item.Guid; add.InventoryData.FolderID = item.ParentGuid; add.InventoryData.CreatorID = item.CreatorID; add.InventoryData.OwnerID = item.OwnerID; add.InventoryData.GroupID = item.GroupID; add.InventoryData.BaseMask = (uint)item.Permissions.BaseMask; add.InventoryData.OwnerMask = (uint)item.Permissions.OwnerMask; add.InventoryData.GroupMask = (uint)item.Permissions.GroupMask; add.InventoryData.EveryoneMask = (uint)item.Permissions.EveryoneMask; add.InventoryData.NextOwnerMask = (uint)item.Permissions.NextOwnerMask; add.InventoryData.GroupOwned = item.GroupOwned; add.InventoryData.TransactionID = queryID; add.InventoryData.Type = (sbyte)item.InventoryType; add.InventoryData.InvType = (sbyte)item.InventoryType; add.InventoryData.Flags = (uint)item.Flags; add.InventoryData.SaleType = (byte)item.SaleType; add.InventoryData.SalePrice = item.SalePrice; add.InventoryData.Name = Utils.StringToBytes(item.Name); add.InventoryData.Description = Utils.StringToBytes(item.Description); add.InventoryData.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate); _Client.Network.SendPacket(add, simulator); return queryID; }
/// <summary> /// Change the Rotation of an object that is either a child or a whole linkset /// </summary> /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param> /// <param name="localID">The objects ID which is local to the simulator the object is in</param> /// <param name="quat">The new scale of the object</param> /// <param name="childOnly">If true, will change rotation of this prim only, not entire linkset</param> public void SetRotation(Simulator simulator, uint localID, Quaternionf quat, bool childOnly) { UpdateType type = UpdateType.Rotation; if (!childOnly) type |= UpdateType.Linked; MultipleObjectUpdatePacket multiObjectUpdate = new MultipleObjectUpdatePacket(); multiObjectUpdate.AgentData.AgentID = Client.Self.AgentID; multiObjectUpdate.AgentData.SessionID = Client.Self.SessionID; multiObjectUpdate.ObjectData = new MultipleObjectUpdatePacket.ObjectDataBlock[1]; multiObjectUpdate.ObjectData[0] = new MultipleObjectUpdatePacket.ObjectDataBlock(); multiObjectUpdate.ObjectData[0].Type = (byte)type; multiObjectUpdate.ObjectData[0].ObjectLocalID = localID; multiObjectUpdate.ObjectData[0].Data = quat.GetBytes(); Client.Network.SendPacket(multiObjectUpdate, simulator); }