* 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:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
69
libsecondlife/examples/Baker/Oven.cs
Normal file
69
libsecondlife/examples/Baker/Oven.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user