/* * Copyright (c) 2006, Second Life Reverse Engineering Team * All rights reserved. * * - Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * - Neither the name of the Second Life Reverse Engineering Team nor the names * of its contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ using System; namespace libsecondlife { /// /// /// public class PrimObject { /// public int PathTwistBegin = 0; /// public float PathEnd = 0; /// public float ProfileBegin = 0; /// public float PathRadiusOffset = 0; /// public float PathSkew = 0; /// public LLVector3 Position = LLVector3.Zero; /// public uint ProfileCurve = 0; /// public float PathScaleX = 0; /// public float PathScaleY = 0; /// public LLUUID ID = LLUUID.Zero; /// public uint LocalID = 0; /// public uint ParentID = 0; /// public LLUUID GroupID = LLUUID.Zero; /// public uint Material = 0; /// public string Name = ""; /// public string Description; /// public float PathShearX = 0; /// public float PathShearY = 0; /// public float PathTaperX = 0; /// public float PathTaperY = 0; /// public float ProfileEnd = 0; /// public float PathBegin = 0; /// public uint PathCurve = 0; /// public LLVector3 Scale = LLVector3.Zero; /// public int PathTwist = 0; /// public ObjectManager.PCode PCode; /// public TextureEntry Textures; /// public TextureAnimation TextureAnim; /// public uint ProfileHollow = 0; /// public float PathRevolutions = 0; /// public LLQuaternion Rotation = LLQuaternion.Identity; /// public uint State; /// public string Text; /// public PrimFlexibleData Flexible; /// public PrimLightData Light; /// public ParticleSystem ParticleSys; /// public ObjectFlags Flags; private SecondLife Client; /// /// /// public PrimObject(SecondLife client) { Client = client; PCode = ObjectManager.PCode.Prim; Flexible = new PrimFlexibleData(); Light = new PrimLightData(); ParticleSys = new ParticleSystem(); Textures = new TextureEntry(); } /// /// /// /// public PrimObject(SecondLife client, LLUUID texture) { Client = client; PCode = ObjectManager.PCode.Prim; Textures = new TextureEntry(); Textures.DefaultTexture.TextureID = texture; } /// /// /// /// /// public static byte PathScaleByte(float pathScale) { // Y = 100 + 100X int scale = (int)Math.Round(100.0f * pathScale); return (byte)(100 + scale); } /// /// /// /// /// public static float PathScaleFloat(byte pathScale) { // Y = -1 + 0.01X return (float)Math.Round((double)pathScale * 0.01d - 1.0d, 6); } /// /// /// /// /// public static byte PathShearByte(float pathShear) { // Y = 256 + 100X int shear = (int)Math.Round(100.0f * pathShear); shear += 256; return (byte)(shear % 256); } /// /// /// /// /// public static float PathShearFloat(byte pathShear) { if (pathShear == 0) return 0.0f; if (pathShear > 150) { // Negative value return ((float)pathShear - 256.0f) / 100.0f; } else { // Positive value return (float)pathShear / 100.0f; } } /// /// /// /// /// public static byte ProfileBeginByte(float profileBegin) { // Y = ceil (200X) return (byte)Math.Round(200.0f * profileBegin); } /// /// /// /// /// public static float ProfileBeginFloat(byte profileBegin) { // Y = 0.005X return (float)Math.Round((double)profileBegin * 0.005d, 6); } /// /// /// /// /// public static byte ProfileEndByte(float profileEnd) { // Y = 200 - 200X int end = (int)Math.Round(200.0d * (double)profileEnd); return (byte)(200 - end); } /// /// /// /// /// public static float ProfileEndFloat(byte profileEnd) { // Y = 1 - 0.005X return (float)Math.Round(1.0d - ((double)profileEnd * 0.005d), 6); } /// /// /// /// /// public static byte PathBeginByte(float pathBegin) { // Y = 100X return (byte)Convert.ToInt16(100.0f * pathBegin); } /// /// /// /// /// public static float PathBeginFloat(byte pathBegin) { // Y = X / 100 return (float)pathBegin / 100.0f; } /// /// /// /// /// public static byte PathEndByte(float pathEnd) { // Y = 100 - 100X int end = (int)Math.Round(100.0f * pathEnd); return (byte)(100 - end); } /// /// /// /// /// public static float PathEndFloat(byte pathEnd) { // Y = 1 - X / 100 return 1.0f - (float)pathEnd / 100.0f; } /// /// /// /// /// public static sbyte PathRadiusOffsetByte(float pathRadiusOffset) { // Y = 256 + 100X return (sbyte)PathShearByte(pathRadiusOffset); } /// /// /// /// /// public static float PathRadiusOffsetFloat(sbyte pathRadiusOffset) { // Y = X / 100 return (float)pathRadiusOffset / 100.0f; } /// /// /// /// /// public static byte PathRevolutionsByte(float pathRevolutions) { // Y = 66.5X - 66 int revolutions = (int)Math.Round(66.5d * (double)pathRevolutions); return (byte)(revolutions - 66); } /// /// /// /// /// public static float PathRevolutionsFloat(byte pathRevolutions) { // Y = 1 + 0.015X return (float)Math.Round(1.0d + (double)pathRevolutions * 0.015d, 6); } /// /// /// /// /// public static sbyte PathSkewByte(float pathSkew) { return PathTaperByte(pathSkew); } /// /// /// /// /// public static float PathSkewFloat(sbyte pathSkew) { return PathTaperFloat(pathSkew); } /// /// /// /// /// public static sbyte PathTaperByte(float pathTaper) { // Y = 256 + 100X return (sbyte)PathShearByte(pathTaper); } /// /// /// /// /// public static float PathTaperFloat(sbyte pathTaper) { return (float)pathTaper / 100.0f; } /// /// /// /// /// /// public int SetExtraParamsFromBytes(byte[] data, int pos) { int i = pos; int totalLength = 1; if (data.Length == 0) return 0; byte extraParamCount = data[i++]; for (int k = 0; k < extraParamCount; k++) { ExtraParamType type = (ExtraParamType)(data[i++] + (data[i++] << 8)); uint paramLength = (uint)(data[i++] + (data[i++] << 8) + (data[i++] << 16) + (data[i++] << 24)); if (type == ExtraParamType.Flexible) { Flexible = new PrimFlexibleData(data, i); } else if (type == ExtraParamType.Light) { Light = new PrimLightData(data, i); } i += (int)paramLength; totalLength += (int)paramLength + 6; } return totalLength; } public override string ToString() { string output = ""; output += (Name != "") ? Name : "Unnamed"; output += ": " + ((Description != "") ? Description : "No description") + Environment.NewLine; output += "ID: " + ID + Environment.NewLine; output += "GroupID: " + GroupID + Environment.NewLine; output += "ParentID: " + ParentID + Environment.NewLine; output += "LocalID: " + LocalID + Environment.NewLine; output += "Flags: " + Flags + Environment.NewLine; output += "State: " + State + Environment.NewLine; output += "PCode: " + PCode + Environment.NewLine; output += "Material: " + Material + Environment.NewLine; output += "PathBegin: " + PathBegin + Environment.NewLine; output += "PathEnd: " + PathEnd + Environment.NewLine; return output; } } /// /// /// [Flags] public enum ObjectFlags { None = 0, Physics = 1 << 0, CreateSelected = 1 << 1, Script = 1 << 6, Touch = 1 << 7, Money = 1 << 9, Phantom = 1 << 10, Temp = 1 << 30 } /// /// /// public enum ExtraParamType : ushort { Flexible = 0x10, Light = 0x20 } /// /// /// public class PrimFlexibleData { /// public int Softness; /// public float Gravity; /// public float Drag; /// public float Wind; /// public float Tension; /// public LLVector3 Force = LLVector3.Zero; /// /// /// public PrimFlexibleData() { } /// /// /// /// /// public PrimFlexibleData(byte[] data, int pos) { FromBytes(data, pos); } /// /// /// /// public byte[] ToBytes() { byte[] data = new byte[16]; int i = 0; data[i] = (byte)((Softness & 2) << 6); data[i + 1] = (byte)((Softness & 1) << 7); data[i++] |= (byte)((byte)(Tension * 10.0f) & 0x7F); data[i++] |= (byte)((byte)(Drag * 10.0f) & 0x7F); data[i++] = (byte)((Gravity + 10.0f) * 10.0f); data[i++] = (byte)(Wind * 10.0f); Force.GetBytes().CopyTo(data, i); return data; } private void FromBytes(byte[] data, int pos) { int i = pos; Softness = ((data[i] & 0x80) >> 6) | ((data[i + 1] & 0x80) >> 7); Tension = (data[i++] & 0x7F) / 10.0f; Drag = (data[i++] & 0x7F) / 10.0f; Gravity = (data[i++] / 10.0f) - 10.0f; Wind = data[i++] / 10.0f; Force = new LLVector3(data, i); } } /// /// /// public class PrimLightData { /// public byte R, G, B; /// public float Intensity; /// public float Radius; /// public float Falloff; /// /// /// public PrimLightData() { } /// /// /// /// /// public PrimLightData(byte[] data, int pos) { FromBytes(data, pos); } /// /// /// /// public byte[] ToBytes() { byte[] data = new byte[16]; int i = 0; data[i++] = R; data[i++] = G; data[i++] = B; data[i++] = (byte)(Intensity * 255.0f); BitConverter.GetBytes(Radius).CopyTo(data, i); BitConverter.GetBytes(Falloff).CopyTo(data, i + 8); if (!BitConverter.IsLittleEndian) { Array.Reverse(data, i, 4); Array.Reverse(data, i + 8, 4); } return data; } private void FromBytes(byte[] data, int pos) { int i = pos; R = data[i++]; G = data[i++]; B = data[i++]; Intensity = data[i++] / 255.0f; if (!BitConverter.IsLittleEndian) { Array.Reverse(data, i, 4); Array.Reverse(data, i + 8, 4); } Radius = BitConverter.ToSingle(data, i); Falloff = BitConverter.ToSingle(data, i + 8); } } }