* Client.Self.Position now does acceleration/velocity interpolation

* Added LLVector3 * float operator
* Adding Oven.cs to Baker (will be moved in to libsecondlife later) that does the first baby steps of baking
* Added the missing Helpers.GetResourceStream() function
* Changed readonly Settings values to const


git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@1110 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
John Hurliman
2007-04-09 08:03:12 +00:00
parent 3c81807d8b
commit f44c012f60
14 changed files with 176 additions and 23 deletions

View File

@@ -958,5 +958,16 @@ namespace libsecondlife
object list = serializer.Deserialize(reader);
return (List<Packet>)list;
}
/// <summary>
///
/// </summary>
/// <param name="resourceName"></param>
/// <returns></returns>
public static System.IO.Stream GetResourceStream(string resourceName)
{
System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly();
return a.GetManifestResourceStream("libsecondlife.Resources." + resourceName);
}
}
}

View File

@@ -346,9 +346,15 @@ namespace libsecondlife
#endregion Public Properties
internal ObjectData data = new ObjectData();
internal ObjectData data;
internal DateTime lastInterpolation;
/// <summary>
///
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
LLObject llobj = obj as LLObject;
@@ -357,6 +363,10 @@ namespace libsecondlife
return ID.Equals(llobj.ID);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return ID.GetHashCode();

View File

@@ -699,6 +699,7 @@ namespace libsecondlife
internal uint sittingOn = 0;
internal string teleportMessage = String.Empty;
internal DateTime lastInterpolation;
private SecondLife Client;
private TeleportStatus TeleportStat = TeleportStatus.None;

View File

@@ -334,7 +334,7 @@ namespace libsecondlife
Camera.CameraUpAxis = new LLVector3(0, 0, 0.9999f);
Camera.Far = 384.0f;
UpdateTimer = new Timer(Client.Settings.AGENT_UPDATE_INTERVAL);
UpdateTimer = new Timer(Settings.AGENT_UPDATE_INTERVAL);
UpdateTimer.Elapsed += new ElapsedEventHandler(UpdateTimer_Elapsed);
UpdateTimer.Enabled = Client.Settings.SEND_AGENT_UPDATES;
}

View File

@@ -528,7 +528,7 @@ namespace libsecondlife
else
{
// Keep the Inbox size within a certain capacity
while (simulator.PacketArchive.Count >= Client.Settings.PACKET_ARCHIVE_SIZE)
while (simulator.PacketArchive.Count >= Settings.PACKET_ARCHIVE_SIZE)
{
simulator.PacketArchive.Dequeue(); simulator.PacketArchive.Dequeue();
simulator.PacketArchive.Dequeue(); simulator.PacketArchive.Dequeue();

View File

@@ -451,12 +451,18 @@ namespace libsecondlife
#endregion
private const float HAVOK_TIMESTEP = 1.0f / 45.0f;
/// <summary>
/// Reference to the SecondLife client
/// </summary>
protected SecondLife Client;
private System.Timers.Timer InterpolationTimer;
/// <summary>
/// Instantiates a new ObjectManager class. This class should only be accessed
/// through SecondLife.Objects, client applications should never create their own
@@ -495,6 +501,12 @@ namespace libsecondlife
Client.Network.RegisterCallback(PacketType.ObjectUpdateCached, new NetworkManager.PacketCallback(CachedUpdateHandler));
Client.Network.RegisterCallback(PacketType.KillObject, new NetworkManager.PacketCallback(KillObjectHandler));
Client.Network.RegisterCallback(PacketType.ObjectPropertiesFamily, new NetworkManager.PacketCallback(ObjectPropertiesFamilyHandler));
// If the callbacks aren't registered there's not point in doing client-side path prediction,
// so we set it up here
InterpolationTimer = new System.Timers.Timer(Settings.INTERPOLATION_UPDATE);
InterpolationTimer.Elapsed += new System.Timers.ElapsedEventHandler(InterpolationTimer_Elapsed);
InterpolationTimer.Start();
}
#region Action Methods
@@ -1962,7 +1974,6 @@ namespace libsecondlife
#endregion
#region Utility Functions
protected void SetAvatarSelfSittingOn(uint localid)
@@ -1980,8 +1991,30 @@ namespace libsecondlife
s.Dilation = (float)dilation / 65535.0f;
}
#endregion
protected void InterpolationTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (Client.Network.Connected)
{
// For now we only update Client.Self since there is no object tracking
// built in to the library
// Only do movement interpolation (extrapolation) when there is a non-zero velocity but
// no acceleration
if (Client.Self.Velocity != LLVector3.Zero || Client.Self.Acceleration != LLVector3.Zero)
{
TimeSpan interval = DateTime.Now - Client.Self.lastInterpolation;
float adjSeconds = (float)interval.TotalSeconds * Client.Network.CurrentSim.Dilation;
Client.Self.Position += (Client.Self.Velocity + (0.5f * (adjSeconds - HAVOK_TIMESTEP)) *
Client.Self.Acceleration) * adjSeconds;
}
}
// Make sure the last interpolated time is always updated
Client.Self.lastInterpolation = DateTime.Now;
}
#endregion
#region Event Notification
@@ -2068,7 +2101,6 @@ namespace libsecondlife
#endregion
#region Subclass Indirection
/// <summary>

View File

@@ -47,22 +47,24 @@ namespace libsecondlife
/// <summary>The initial size of the packet inbox, where packets are
/// stored before processing</summary>
public const int PACKET_INBOX_SIZE = 100;
/// <summary>Maximum size of packet that we want to send over the wire</summary>
public readonly int MAX_PACKET_SIZE = 1200;
public const int MAX_PACKET_SIZE = 1200;
/// <summary>Millisecond interval between ticks, where all ACKs are
/// sent out and the age of unACKed packets is checked</summary>
public readonly int NETWORK_TICK_LENGTH = 500;
public const int NETWORK_TICK_LENGTH = 500;
/// <summary>The maximum value of a packet sequence number before it
/// rolls over back to one</summary>
public readonly int MAX_SEQUENCE = 0xFFFFFF;
public const int MAX_SEQUENCE = 0xFFFFFF;
/// <summary>The maximum size of the sequence number archive, used to
/// check for resent and/or duplicate packets</summary>
public readonly int PACKET_ARCHIVE_SIZE = 50;
public const int PACKET_ARCHIVE_SIZE = 50;
/// <summary>Number of milliseconds between sending pings to each sim</summary>
public readonly int PING_INTERVAL = 2200;
public const int PING_INTERVAL = 2200;
/// <summary>Number of milliseconds between sending camera updates</summary>
public readonly int AGENT_UPDATE_INTERVAL = 500;
public const int AGENT_UPDATE_INTERVAL = 500;
/// <summary>Number of milliseconds between updating the current
/// positions of moving, non-accelerating and non-colliding objects</summary>
public const int INTERPOLATION_UPDATE = 250;
/// <summary>Number of milliseconds before a teleport attempt will time
/// out</summary>

View File

@@ -294,7 +294,7 @@ namespace libsecondlife
Estate = new EstateTools(Client);
Network = client.Network;
PacketArchive = new Queue<uint>(Client.Settings.PACKET_ARCHIVE_SIZE);
PacketArchive = new Queue<uint>(Settings.PACKET_ARCHIVE_SIZE);
InBytes = new Queue<ulong>(Client.Settings.STATS_QUEUE_SIZE);
OutBytes = new Queue<ulong>(Client.Settings.STATS_QUEUE_SIZE);
@@ -306,13 +306,13 @@ namespace libsecondlife
// Initialize the callback for receiving a new packet
ReceivedData = new AsyncCallback(OnReceivedData);
AckTimer = new System.Timers.Timer(Client.Settings.NETWORK_TICK_LENGTH);
AckTimer = new System.Timers.Timer(Settings.NETWORK_TICK_LENGTH);
AckTimer.Elapsed += new System.Timers.ElapsedEventHandler(AckTimer_Elapsed);
StatsTimer = new System.Timers.Timer(1000);
StatsTimer.Elapsed += new System.Timers.ElapsedEventHandler(StatsTimer_Elapsed);
PingTimer = new System.Timers.Timer(Client.Settings.PING_INTERVAL);
PingTimer = new System.Timers.Timer(Settings.PING_INTERVAL);
PingTimer.Elapsed += new System.Timers.ElapsedEventHandler(PingTimer_Elapsed);
}
@@ -425,7 +425,7 @@ namespace libsecondlife
// Set the sequence number
lock (SequenceLock)
{
if (Sequence > Client.Settings.MAX_SEQUENCE)
if (Sequence > Settings.MAX_SEQUENCE)
Sequence = 1;
else
Sequence++;

View File

@@ -310,11 +310,11 @@ namespace libsecondlife
public struct LLVector3
{
/// <summary>X value</summary>
[XmlAttribute("x"), DefaultValue(0)] public float X;
public float X;
/// <summary>Y value</summary>
[XmlAttribute("y"), DefaultValue(0)] public float Y;
public float Y;
/// <summary>Z value</summary>
[XmlAttribute("z"), DefaultValue(0)] public float Z;
public float Z;
/// <summary>
/// Constructor, builds a single-precision vector from a
@@ -509,6 +509,28 @@ namespace libsecondlife
return new LLVector3(lhs.X - rhs.X,lhs.Y - rhs.Y, lhs.Z - rhs.Z);
}
/// <summary>
///
/// </summary>
/// <param name="vec"></param>
/// <param name="val"></param>
/// <returns></returns>
public static LLVector3 operator *(LLVector3 vec, float val)
{
return new LLVector3(vec.X * val, vec.Y * val, vec.Z * val);
}
/// <summary>
///
/// </summary>
/// <param name="val"></param>
/// <param name="vec"></param>
/// <returns></returns>
public static LLVector3 operator *(float val, LLVector3 vec)
{
return new LLVector3(vec.X * val, vec.Y * val, vec.Z * val);
}
public static LLVector3 operator *(LLVector3 vec, LLQuaternion quat)
{
LLQuaternion vq = new LLQuaternion(vec.X, vec.Y, vec.Z, 0);

View File

@@ -41,6 +41,7 @@
<DependentUpon>frmBaker.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Oven.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="Baker.cs" />
@@ -67,4 +68,4 @@
<Name>libsecondlife</Name>
</ProjectReference>
</ItemGroup>
</Project>
</Project>

View File

@@ -0,0 +1,69 @@
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace Baker
{
public static class Oven
{
public static Bitmap ModifyAlphaMask(Bitmap alpha, byte weight, float ramp)
{
// Create the new modifiable image (our canvas)
int width = alpha.Width;
int height = alpha.Height;
int pixelFormatSize = Image.GetPixelFormatSize(alpha.PixelFormat) / 8;
int stride = width * pixelFormatSize;
byte[] data = new byte[stride * height];
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr pointer = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0);
Bitmap modified = new Bitmap(width, height, stride, alpha.PixelFormat, pointer);
// Copy the existing alpha mask to the canvas
Graphics g = Graphics.FromImage(modified);
g.DrawImageUnscaledAndClipped(alpha, new Rectangle(0, 0, width, height));
g.Dispose();
// Modify the canvas based on the input weight and ramp values
// TODO: use the ramp
// TODO: only bother with the alpha values
for (int i = 0; i < data.Length; i++)
{
if (data[i] < weight) data[i] = 0;
}
return modified;
}
public static Bitmap ApplyAlphaMask(Bitmap source, Bitmap alpha)
{
// Create the new modifiable image (our canvas)
int width = source.Width;
int height = source.Height;
if (alpha.Width != width || alpha.Height != height ||
alpha.PixelFormat != source.PixelFormat)
{
throw new Exception("Source image and alpha mask formats do not match");
}
int pixelFormatSize = Image.GetPixelFormatSize(source.PixelFormat) / 8;
int stride = width * pixelFormatSize;
byte[] data = new byte[stride * height];
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr pointer = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0);
Bitmap modified = new Bitmap(width, height, stride, source.PixelFormat, pointer);
// Copy the source image to the canvas
Graphics g = Graphics.FromImage(modified);
g.DrawImageUnscaledAndClipped(source, new Rectangle(0, 0, width, height));
g.Dispose();
// Get access to the pixel data for the alpha mask (probably using lockbits)
// Combine the alpha mask alpha bytes in to the canvas
return modified;
}
}
}

View File

@@ -47,6 +47,7 @@ namespace Baker
this.pic1.Size = new System.Drawing.Size(256, 256);
this.pic1.TabIndex = 0;
this.pic1.TabStop = false;
this.pic1.AutoSize = true;
//
// cmdLoadPic1
//
@@ -66,6 +67,7 @@ namespace Baker
this.pic2.Size = new System.Drawing.Size(256, 256);
this.pic2.TabIndex = 2;
this.pic2.TabStop = false;
this.pic1.AutoSize = true;
//
// pic3
//
@@ -75,6 +77,7 @@ namespace Baker
this.pic3.Size = new System.Drawing.Size(256, 256);
this.pic3.TabIndex = 3;
this.pic3.TabStop = false;
this.pic1.AutoSize = true;
//
// cmdLoadPic2
//
@@ -130,3 +133,4 @@ namespace Baker
}
}

View File

@@ -23,7 +23,8 @@ namespace Baker
if (stream != null)
{
pic1.Image = OpenJPEGNet.LoadTGAClass.LoadTGA(stream);
Bitmap alphaMask = OpenJPEGNet.LoadTGAClass.LoadTGA(stream);
pic1.Image = Oven.ModifyAlphaMask(alphaMask, 245, 0.0f);
}
else
{

View File

@@ -404,7 +404,7 @@ namespace libsecondlife.Utilities.Assets
request.AssetBlock.TransactionID = upload.ID;
request.AssetBlock.Type = (sbyte)type;
if (data.Length + 100 < Client.Settings.MAX_PACKET_SIZE)
if (data.Length + 100 < Settings.MAX_PACKET_SIZE)
{
// The whole asset will fit in this packet, makes things easy
request.AssetBlock.AssetData = data;