corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using System.Collections.Generic;
29 using OpenMetaverse.StructuredData;
30  
31 namespace OpenMetaverse
32 {
33 public partial class Primitive : IEquatable<Primitive>
34 {
35 // Used for packing and unpacking parameters
36 protected const float CUT_QUANTA = 0.00002f;
37 protected const float SCALE_QUANTA = 0.01f;
38 protected const float SHEAR_QUANTA = 0.01f;
39 protected const float TAPER_QUANTA = 0.01f;
40 protected const float REV_QUANTA = 0.015f;
41 protected const float HOLLOW_QUANTA = 0.00002f;
42  
43 #region Subclasses
44  
45 /// <summary>
46 /// Parameters used to construct a visual representation of a primitive
47 /// </summary>
48 public struct ConstructionData
49 {
50 private const byte PROFILE_MASK = 0x0F;
51 private const byte HOLE_MASK = 0xF0;
52  
53 /// <summary></summary>
54 public byte profileCurve;
55 /// <summary></summary>
56 public PathCurve PathCurve;
57 /// <summary></summary>
58 public float PathEnd;
59 /// <summary></summary>
60 public float PathRadiusOffset;
61 /// <summary></summary>
62 public float PathSkew;
63 /// <summary></summary>
64 public float PathScaleX;
65 /// <summary></summary>
66 public float PathScaleY;
67 /// <summary></summary>
68 public float PathShearX;
69 /// <summary></summary>
70 public float PathShearY;
71 /// <summary></summary>
72 public float PathTaperX;
73 /// <summary></summary>
74 public float PathTaperY;
75 /// <summary></summary>
76 public float PathBegin;
77 /// <summary></summary>
78 public float PathTwist;
79 /// <summary></summary>
80 public float PathTwistBegin;
81 /// <summary></summary>
82 public float PathRevolutions;
83 /// <summary></summary>
84 public float ProfileBegin;
85 /// <summary></summary>
86 public float ProfileEnd;
87 /// <summary></summary>
88 public float ProfileHollow;
89  
90 /// <summary></summary>
91 public Material Material;
92 /// <summary></summary>
93 public byte State;
94 /// <summary></summary>
95 public PCode PCode;
96  
97 #region Properties
98  
99 /// <summary>Attachment point to an avatar</summary>
100 public AttachmentPoint AttachmentPoint
101 {
102 get { return (AttachmentPoint)Utils.SwapWords(State); }
103 set { State = (byte)Utils.SwapWords((byte)value); }
104 }
105  
106 /// <summary></summary>
107 public ProfileCurve ProfileCurve
108 {
109 get { return (ProfileCurve)(profileCurve & PROFILE_MASK); }
110 set
111 {
112 profileCurve &= HOLE_MASK;
113 profileCurve |= (byte)value;
114 }
115 }
116  
117 /// <summary></summary>
118 public HoleType ProfileHole
119 {
120 get { return (HoleType)(profileCurve & HOLE_MASK); }
121 set
122 {
123 profileCurve &= PROFILE_MASK;
124 profileCurve |= (byte)value;
125 }
126 }
127  
128 /// <summary></summary>
129 public Vector2 PathBeginScale
130 {
131 get
132 {
133 Vector2 begin = new Vector2(1f, 1f);
134 if (PathScaleX > 1f)
135 begin.X = 2f - PathScaleX;
136 if (PathScaleY > 1f)
137 begin.Y = 2f - PathScaleY;
138 return begin;
139 }
140 }
141  
142 /// <summary></summary>
143 public Vector2 PathEndScale
144 {
145 get
146 {
147 Vector2 end = new Vector2(1f, 1f);
148 if (PathScaleX < 1f)
149 end.X = PathScaleX;
150 if (PathScaleY < 1f)
151 end.Y = PathScaleY;
152 return end;
153 }
154 }
155  
156 #endregion Properties
157  
158 /// <summary>
159 /// Calculdates hash code for prim construction data
160 /// </summary>
161 /// <returns>The has</returns>
162 public override int GetHashCode()
163 {
164 return profileCurve.GetHashCode()
165 ^ PathCurve.GetHashCode()
166 ^ PathEnd.GetHashCode()
167 ^ PathRadiusOffset.GetHashCode()
168 ^ PathSkew.GetHashCode()
169 ^ PathScaleX.GetHashCode()
170 ^ PathScaleY.GetHashCode()
171 ^ PathShearX.GetHashCode()
172 ^ PathShearY.GetHashCode()
173 ^ PathTaperX.GetHashCode()
174 ^ PathTaperY.GetHashCode()
175 ^ PathBegin.GetHashCode()
176 ^ PathTwist.GetHashCode()
177 ^ PathTwistBegin.GetHashCode()
178 ^ PathRevolutions.GetHashCode()
179 ^ ProfileBegin.GetHashCode()
180 ^ ProfileEnd.GetHashCode()
181 ^ ProfileHollow.GetHashCode()
182 ^ Material.GetHashCode()
183 ^ State.GetHashCode()
184 ^ PCode.GetHashCode();
185 }
186 }
187  
188 /// <summary>
189 /// Information on the flexible properties of a primitive
190 /// </summary>
191 public class FlexibleData
192 {
193 /// <summary></summary>
194 public int Softness;
195 /// <summary></summary>
196 public float Gravity;
197 /// <summary></summary>
198 public float Drag;
199 /// <summary></summary>
200 public float Wind;
201 /// <summary></summary>
202 public float Tension;
203 /// <summary></summary>
204 public Vector3 Force;
205  
206 /// <summary>
207 /// Default constructor
208 /// </summary>
209 public FlexibleData()
210 {
211 }
212  
213 /// <summary>
214 ///
215 /// </summary>
216 /// <param name="data"></param>
217 /// <param name="pos"></param>
218 public FlexibleData(byte[] data, int pos)
219 {
220 if (data.Length >= 5)
221 {
222 Softness = ((data[pos] & 0x80) >> 6) | ((data[pos + 1] & 0x80) >> 7);
223  
224 Tension = (float)(data[pos++] & 0x7F) / 10.0f;
225 Drag = (float)(data[pos++] & 0x7F) / 10.0f;
226 Gravity = (float)(data[pos++] / 10.0f) - 10.0f;
227 Wind = (float)data[pos++] / 10.0f;
228 Force = new Vector3(data, pos);
229 }
230 else
231 {
232 Softness = 0;
233  
234 Tension = 0.0f;
235 Drag = 0.0f;
236 Gravity = 0.0f;
237 Wind = 0.0f;
238 Force = Vector3.Zero;
239 }
240 }
241  
242 /// <summary>
243 ///
244 /// </summary>
245 /// <returns></returns>
246 public byte[] GetBytes()
247 {
248 byte[] data = new byte[16];
249 int i = 0;
250  
251 // Softness is packed in the upper bits of tension and drag
252 data[i] = (byte)((Softness & 2) << 6);
253 data[i + 1] = (byte)((Softness & 1) << 7);
254  
255 data[i++] |= (byte)((byte)(Tension * 10.01f) & 0x7F);
256 data[i++] |= (byte)((byte)(Drag * 10.01f) & 0x7F);
257 data[i++] = (byte)((Gravity + 10.0f) * 10.01f);
258 data[i++] = (byte)(Wind * 10.01f);
259  
260 Force.GetBytes().CopyTo(data, i);
261  
262 return data;
263 }
264  
265 /// <summary>
266 ///
267 /// </summary>
268 /// <returns></returns>
269 public OSD GetOSD()
270 {
271 OSDMap map = new OSDMap();
272  
273 map["simulate_lod"] = OSD.FromInteger(Softness);
274 map["gravity"] = OSD.FromReal(Gravity);
275 map["air_friction"] = OSD.FromReal(Drag);
276 map["wind_sensitivity"] = OSD.FromReal(Wind);
277 map["tension"] = OSD.FromReal(Tension);
278 map["user_force"] = OSD.FromVector3(Force);
279  
280 return map;
281 }
282  
283 public static FlexibleData FromOSD(OSD osd)
284 {
285 FlexibleData flex = new FlexibleData();
286  
287 if (osd.Type == OSDType.Map)
288 {
289 OSDMap map = (OSDMap)osd;
290  
291 flex.Softness = map["simulate_lod"].AsInteger();
292 flex.Gravity = (float)map["gravity"].AsReal();
293 flex.Drag = (float)map["air_friction"].AsReal();
294 flex.Wind = (float)map["wind_sensitivity"].AsReal();
295 flex.Tension = (float)map["tension"].AsReal();
296 flex.Force = ((OSDArray)map["user_force"]).AsVector3();
297 }
298  
299 return flex;
300 }
301  
302 public override int GetHashCode()
303 {
304 return
305 Softness.GetHashCode() ^
306 Gravity.GetHashCode() ^
307 Drag.GetHashCode() ^
308 Wind.GetHashCode() ^
309 Tension.GetHashCode() ^
310 Force.GetHashCode();
311 }
312 }
313  
314 /// <summary>
315 /// Information on the light properties of a primitive
316 /// </summary>
317 public class LightData
318 {
319 /// <summary></summary>
320 public Color4 Color;
321 /// <summary></summary>
322 public float Intensity;
323 /// <summary></summary>
324 public float Radius;
325 /// <summary></summary>
326 public float Cutoff;
327 /// <summary></summary>
328 public float Falloff;
329  
330 /// <summary>
331 /// Default constructor
332 /// </summary>
333 public LightData()
334 {
335 }
336  
337 /// <summary>
338 ///
339 /// </summary>
340 /// <param name="data"></param>
341 /// <param name="pos"></param>
342 public LightData(byte[] data, int pos)
343 {
344 if (data.Length - pos >= 16)
345 {
346 Color = new Color4(data, pos, false);
347 Radius = Utils.BytesToFloat(data, pos + 4);
348 Cutoff = Utils.BytesToFloat(data, pos + 8);
349 Falloff = Utils.BytesToFloat(data, pos + 12);
350  
351 // Alpha in color is actually intensity
352 Intensity = Color.A;
353 Color.A = 1f;
354 }
355 else
356 {
357 Color = Color4.Black;
358 Radius = 0f;
359 Cutoff = 0f;
360 Falloff = 0f;
361 Intensity = 0f;
362 }
363 }
364  
365 /// <summary>
366 ///
367 /// </summary>
368 /// <returns></returns>
369 public byte[] GetBytes()
370 {
371 byte[] data = new byte[16];
372  
373 // Alpha channel in color is intensity
374 Color4 tmpColor = Color;
375 tmpColor.A = Intensity;
376 tmpColor.GetBytes().CopyTo(data, 0);
377 Utils.FloatToBytes(Radius).CopyTo(data, 4);
378 Utils.FloatToBytes(Cutoff).CopyTo(data, 8);
379 Utils.FloatToBytes(Falloff).CopyTo(data, 12);
380  
381 return data;
382 }
383  
384 public OSD GetOSD()
385 {
386 OSDMap map = new OSDMap();
387  
388 map["color"] = OSD.FromColor4(Color);
389 map["intensity"] = OSD.FromReal(Intensity);
390 map["radius"] = OSD.FromReal(Radius);
391 map["cutoff"] = OSD.FromReal(Cutoff);
392 map["falloff"] = OSD.FromReal(Falloff);
393  
394 return map;
395 }
396  
397 public static LightData FromOSD(OSD osd)
398 {
399 LightData light = new LightData();
400  
401 if (osd.Type == OSDType.Map)
402 {
403 OSDMap map = (OSDMap)osd;
404  
405 light.Color = ((OSDArray)map["color"]).AsColor4();
406 light.Intensity = (float)map["intensity"].AsReal();
407 light.Radius = (float)map["radius"].AsReal();
408 light.Cutoff = (float)map["cutoff"].AsReal();
409 light.Falloff = (float)map["falloff"].AsReal();
410 }
411  
412 return light;
413 }
414  
415 public override int GetHashCode()
416 {
417 return
418 Color.GetHashCode() ^
419 Intensity.GetHashCode() ^
420 Radius.GetHashCode() ^
421 Cutoff.GetHashCode() ^
422 Falloff.GetHashCode();
423 }
424  
425 /// <summary>
426 ///
427 /// </summary>
428 /// <returns></returns>
429 public override string ToString()
430 {
431 return String.Format("Color: {0} Intensity: {1} Radius: {2} Cutoff: {3} Falloff: {4}",
432 Color, Intensity, Radius, Cutoff, Falloff);
433 }
434 }
435  
436 /// <summary>
437 /// Information on the light properties of a primitive as texture map
438 /// </summary>
439 public class LightImage
440 {
441 /// <summary></summary>
442 public UUID LightTexture;
443 /// <summary></summary>
444 public Vector3 Params;
445  
446 /// <summary>
447 /// Default constructor
448 /// </summary>
449 public LightImage()
450 {
451 }
452  
453 /// <summary>
454 ///
455 /// </summary>
456 /// <param name="data"></param>
457 /// <param name="pos"></param>
458 public LightImage(byte[] data, int pos)
459 {
460 if (data.Length - pos >= 28)
461 {
462 LightTexture = new UUID(data, pos);
463 Params = new Vector3(data, pos + 16);
464 }
465 else
466 {
467 LightTexture = UUID.Zero;
468 Params = Vector3.Zero;
469 }
470 }
471  
472 /// <summary>
473 ///
474 /// </summary>
475 /// <returns></returns>
476 public byte[] GetBytes()
477 {
478 byte[] data = new byte[28];
479  
480 // Alpha channel in color is intensity
481 LightTexture.ToBytes(data, 0);
482 Params.ToBytes(data, 16);
483  
484 return data;
485 }
486  
487 public OSD GetOSD()
488 {
489 OSDMap map = new OSDMap();
490  
491 map["texture"] = OSD.FromUUID(LightTexture);
492 map["params"] = OSD.FromVector3(Params);
493  
494 return map;
495 }
496  
497 public static LightImage FromOSD(OSD osd)
498 {
499 LightImage light = new LightImage();
500  
501 if (osd.Type == OSDType.Map)
502 {
503 OSDMap map = (OSDMap)osd;
504  
505 light.LightTexture = map["texture"].AsUUID();
506 light.Params = map["params"].AsVector3();
507 }
508  
509 return light;
510 }
511  
512 public override int GetHashCode()
513 {
514 return LightTexture.GetHashCode() ^ Params.GetHashCode();
515 }
516  
517 /// <summary>
518 ///
519 /// </summary>
520 /// <returns></returns>
521 public override string ToString()
522 {
523 return String.Format("LightTexture: {0} Params; {1]", LightTexture, Params);
524 }
525 }
526  
527 /// <summary>
528 /// Information on the sculpt properties of a sculpted primitive
529 /// </summary>
530 public class SculptData
531 {
532 public UUID SculptTexture;
533 private byte type;
534  
535 public SculptType Type
536 {
537 get { return (SculptType)(type & 7); }
538 set { type = (byte)value; }
539 }
540  
541 /// <summary>
542 /// Render inside out (inverts the normals).
543 /// </summary>
544 public bool Invert
545 {
546 get { return ((type & (byte)SculptType.Invert) != 0); }
547 }
548  
549 /// <summary>
550 /// Render an X axis mirror of the sculpty.
551 /// </summary>
552 public bool Mirror
553 {
554 get { return ((type & (byte)SculptType.Mirror) != 0); }
555 }
556  
557 /// <summary>
558 /// Default constructor
559 /// </summary>
560 public SculptData()
561 {
562 }
563  
564 /// <summary>
565 ///
566 /// </summary>
567 /// <param name="data"></param>
568 /// <param name="pos"></param>
569 public SculptData(byte[] data, int pos)
570 {
571 if (data.Length >= 17)
572 {
573 SculptTexture = new UUID(data, pos);
574 type = data[pos + 16];
575 }
576 else
577 {
578 SculptTexture = UUID.Zero;
579 type = (byte)SculptType.None;
580 }
581 }
582  
583 public byte[] GetBytes()
584 {
585 byte[] data = new byte[17];
586  
587 SculptTexture.GetBytes().CopyTo(data, 0);
588 data[16] = type;
589  
590 return data;
591 }
592  
593 public OSD GetOSD()
594 {
595 OSDMap map = new OSDMap();
596  
597 map["texture"] = OSD.FromUUID(SculptTexture);
598 map["type"] = OSD.FromInteger(type);
599  
600 return map;
601 }
602  
603 public static SculptData FromOSD(OSD osd)
604 {
605 SculptData sculpt = new SculptData();
606  
607 if (osd.Type == OSDType.Map)
608 {
609 OSDMap map = (OSDMap)osd;
610  
611 sculpt.SculptTexture = map["texture"].AsUUID();
612 sculpt.type = (byte)map["type"].AsInteger();
613 }
614  
615 return sculpt;
616 }
617  
618 public override int GetHashCode()
619 {
620 return SculptTexture.GetHashCode() ^ type.GetHashCode();
621 }
622 }
623  
624 /// <summary>
625 /// Extended properties to describe an object
626 /// </summary>
627 public class ObjectProperties
628 {
629 /// <summary></summary>
630 public UUID ObjectID;
631 /// <summary></summary>
632 public UUID CreatorID;
633 /// <summary></summary>
634 public UUID OwnerID;
635 /// <summary></summary>
636 public UUID GroupID;
637 /// <summary></summary>
638 public DateTime CreationDate;
639 /// <summary></summary>
640 public Permissions Permissions;
641 /// <summary></summary>
642 public int OwnershipCost;
643 /// <summary></summary>
644 public SaleType SaleType;
645 /// <summary></summary>
646 public int SalePrice;
647 /// <summary></summary>
648 public byte AggregatePerms;
649 /// <summary></summary>
650 public byte AggregatePermTextures;
651 /// <summary></summary>
652 public byte AggregatePermTexturesOwner;
653 /// <summary></summary>
654 public ObjectCategory Category;
655 /// <summary></summary>
656 public short InventorySerial;
657 /// <summary></summary>
658 public UUID ItemID;
659 /// <summary></summary>
660 public UUID FolderID;
661 /// <summary></summary>
662 public UUID FromTaskID;
663 /// <summary></summary>
664 public UUID LastOwnerID;
665 /// <summary></summary>
666 public string Name;
667 /// <summary></summary>
668 public string Description;
669 /// <summary></summary>
670 public string TouchName;
671 /// <summary></summary>
672 public string SitName;
673 /// <summary></summary>
674 public UUID[] TextureIDs;
675  
676 /// <summary>
677 /// Default constructor
678 /// </summary>
679 public ObjectProperties()
680 {
681 Name = String.Empty;
682 Description = String.Empty;
683 TouchName = String.Empty;
684 SitName = String.Empty;
685 }
686  
687 /// <summary>
688 /// Set the properties that are set in an ObjectPropertiesFamily packet
689 /// </summary>
690 /// <param name="props"><seealso cref="ObjectProperties"/> that has
691 /// been partially filled by an ObjectPropertiesFamily packet</param>
692 public void SetFamilyProperties(ObjectProperties props)
693 {
694 ObjectID = props.ObjectID;
695 OwnerID = props.OwnerID;
696 GroupID = props.GroupID;
697 Permissions = props.Permissions;
698 OwnershipCost = props.OwnershipCost;
699 SaleType = props.SaleType;
700 SalePrice = props.SalePrice;
701 Category = props.Category;
702 LastOwnerID = props.LastOwnerID;
703 Name = props.Name;
704 Description = props.Description;
705 }
706  
707 public byte[] GetTextureIDBytes()
708 {
709 if (TextureIDs == null || TextureIDs.Length == 0)
710 return Utils.EmptyBytes;
711  
712 byte[] bytes = new byte[16 * TextureIDs.Length];
713 for (int i = 0; i < TextureIDs.Length; i++)
714 TextureIDs[i].ToBytes(bytes, 16 * i);
715  
716 return bytes;
717 }
718 }
719  
720 /// <summary>
721 /// Describes physics attributes of the prim
722 /// </summary>
723 public class PhysicsProperties
724 {
725 /// <summary>Primitive's local ID</summary>
726 public uint LocalID;
727 /// <summary>Density (1000 for normal density)</summary>
728 public float Density;
729 /// <summary>Friction</summary>
730 public float Friction;
731 /// <summary>Gravity multiplier (1 for normal gravity) </summary>
732 public float GravityMultiplier;
733 /// <summary>Type of physics representation of this primitive in the simulator</summary>
734 public PhysicsShapeType PhysicsShapeType;
735 /// <summary>Restitution</summary>
736 public float Restitution;
737  
738 /// <summary>
739 /// Creates PhysicsProperties from OSD
740 /// </summary>
741 /// <param name="osd">OSDMap with incoming data</param>
742 /// <returns>Deserialized PhysicsProperties object</returns>
743 public static PhysicsProperties FromOSD(OSD osd)
744 {
745 PhysicsProperties ret = new PhysicsProperties();
746  
747 if (osd is OSDMap)
748 {
749 OSDMap map = (OSDMap)osd;
750 ret.LocalID = map["LocalID"];
751 ret.Density = map["Density"];
752 ret.Friction = map["Friction"];
753 ret.GravityMultiplier = map["GravityMultiplier"];
754 ret.Restitution = map["Restitution"];
755 ret.PhysicsShapeType = (PhysicsShapeType)map["PhysicsShapeType"].AsInteger();
756 }
757  
758 return ret;
759 }
760  
761 /// <summary>
762 /// Serializes PhysicsProperties to OSD
763 /// </summary>
764 /// <returns>OSDMap with serialized PhysicsProperties data</returns>
765 public OSD GetOSD()
766 {
767 OSDMap map = new OSDMap(6);
768 map["LocalID"] = LocalID;
769 map["Density"] = Density;
770 map["Friction"] = Friction;
771 map["GravityMultiplier"] = GravityMultiplier;
772 map["Restitution"] = Restitution;
773 map["PhysicsShapeType"] = (int)PhysicsShapeType;
774 return map;
775 }
776 }
777  
778 #endregion Subclasses
779  
780 #region Public Members
781  
782 /// <summary></summary>
783 public UUID ID;
784 /// <summary></summary>
785 public UUID GroupID;
786 /// <summary></summary>
787 public uint LocalID;
788 /// <summary></summary>
789 public uint ParentID;
790 /// <summary></summary>
791 public ulong RegionHandle;
792 /// <summary></summary>
793 public PrimFlags Flags;
794 /// <summary>Foliage type for this primitive. Only applicable if this
795 /// primitive is foliage</summary>
796 public Tree TreeSpecies;
797 /// <summary>Unknown</summary>
798 public byte[] ScratchPad;
799 /// <summary></summary>
800 public Vector3 Position;
801 /// <summary></summary>
802 public Vector3 Scale;
803 /// <summary></summary>
804 public Quaternion Rotation = Quaternion.Identity;
805 /// <summary></summary>
806 public Vector3 Velocity;
807 /// <summary></summary>
808 public Vector3 AngularVelocity;
809 /// <summary></summary>
810 public Vector3 Acceleration;
811 /// <summary></summary>
812 public Vector4 CollisionPlane;
813 /// <summary></summary>
814 public FlexibleData Flexible;
815 /// <summary></summary>
816 public LightData Light;
817 /// <summary></summary>
818 public LightImage LightMap;
819 /// <summary></summary>
820 public SculptData Sculpt;
821 /// <summary></summary>
822 public ClickAction ClickAction;
823 /// <summary></summary>
824 public UUID Sound;
825 /// <summary>Identifies the owner if audio or a particle system is
826 /// active</summary>
827 public UUID OwnerID;
828 /// <summary></summary>
829 public SoundFlags SoundFlags;
830 /// <summary></summary>
831 public float SoundGain;
832 /// <summary></summary>
833 public float SoundRadius;
834 /// <summary></summary>
835 public string Text;
836 /// <summary></summary>
837 public Color4 TextColor;
838 /// <summary></summary>
839 public string MediaURL;
840 /// <summary></summary>
841 public JointType Joint;
842 /// <summary></summary>
843 public Vector3 JointPivot;
844 /// <summary></summary>
845 public Vector3 JointAxisOrAnchor;
846 /// <summary></summary>
847 public NameValue[] NameValues;
848 /// <summary></summary>
849 public ConstructionData PrimData;
850 /// <summary></summary>
851 public ObjectProperties Properties;
852 /// <summary>Objects physics engine propertis</summary>
853 public PhysicsProperties PhysicsProps;
854 /// <summary>Extra data about primitive</summary>
855 public object Tag;
856 /// <summary>Indicates if prim is attached to an avatar</summary>
857 public bool IsAttachment;
858 /// <summary>Number of clients referencing this prim</summary>
859 public int ActiveClients = 0;
860  
861 #endregion Public Members
862  
863 #region Properties
864  
865 /// <summary>Uses basic heuristics to estimate the primitive shape</summary>
866 public PrimType Type
867 {
868 get
869 {
870 if (Sculpt != null && Sculpt.Type != SculptType.None && Sculpt.SculptTexture != UUID.Zero)
871 {
872 if (Sculpt.Type == SculptType.Mesh)
873 return PrimType.Mesh;
874 else
875 return PrimType.Sculpt;
876 }
877  
878 bool linearPath = (PrimData.PathCurve == PathCurve.Line || PrimData.PathCurve == PathCurve.Flexible);
879 float scaleY = PrimData.PathScaleY;
880  
881 if (linearPath)
882 {
883 switch (PrimData.ProfileCurve)
884 {
885 case ProfileCurve.Circle:
886 return PrimType.Cylinder;
887 case ProfileCurve.Square:
888 return PrimType.Box;
889 case ProfileCurve.IsoTriangle:
890 case ProfileCurve.EqualTriangle:
891 case ProfileCurve.RightTriangle:
892 return PrimType.Prism;
893 case ProfileCurve.HalfCircle:
894 default:
895 return PrimType.Unknown;
896 }
897 }
898 else
899 {
900 switch (PrimData.PathCurve)
901 {
902 case PathCurve.Flexible:
903 return PrimType.Unknown;
904 case PathCurve.Circle:
905 switch (PrimData.ProfileCurve)
906 {
907 case ProfileCurve.Circle:
908 if (scaleY > 0.75f)
909 return PrimType.Sphere;
910 else
911 return PrimType.Torus;
912 case ProfileCurve.HalfCircle:
913 return PrimType.Sphere;
914 case ProfileCurve.EqualTriangle:
915 return PrimType.Ring;
916 case ProfileCurve.Square:
917 if (scaleY <= 0.75f)
918 return PrimType.Tube;
919 else
920 return PrimType.Unknown;
921 default:
922 return PrimType.Unknown;
923 }
924 case PathCurve.Circle2:
925 if (PrimData.ProfileCurve == ProfileCurve.Circle)
926 return PrimType.Sphere;
927 else
928 return PrimType.Unknown;
929 default:
930 return PrimType.Unknown;
931 }
932 }
933 }
934 }
935  
936 #endregion Properties
937  
938 #region Constructors
939  
940 /// <summary>
941 /// Default constructor
942 /// </summary>
943 public Primitive()
944 {
945 // Default a few null property values to String.Empty
946 Text = String.Empty;
947 MediaURL = String.Empty;
948 }
949  
950 public Primitive(Primitive prim)
951 {
952 ID = prim.ID;
953 GroupID = prim.GroupID;
954 LocalID = prim.LocalID;
955 ParentID = prim.ParentID;
956 RegionHandle = prim.RegionHandle;
957 Flags = prim.Flags;
958 TreeSpecies = prim.TreeSpecies;
959 if (prim.ScratchPad != null)
960 {
961 ScratchPad = new byte[prim.ScratchPad.Length];
962 Buffer.BlockCopy(prim.ScratchPad, 0, ScratchPad, 0, ScratchPad.Length);
963 }
964 else
965 ScratchPad = Utils.EmptyBytes;
966 Position = prim.Position;
967 Scale = prim.Scale;
968 Rotation = prim.Rotation;
969 Velocity = prim.Velocity;
970 AngularVelocity = prim.AngularVelocity;
971 Acceleration = prim.Acceleration;
972 CollisionPlane = prim.CollisionPlane;
973 Flexible = prim.Flexible;
974 Light = prim.Light;
975 LightMap = prim.LightMap;
976 Sculpt = prim.Sculpt;
977 ClickAction = prim.ClickAction;
978 Sound = prim.Sound;
979 OwnerID = prim.OwnerID;
980 SoundFlags = prim.SoundFlags;
981 SoundGain = prim.SoundGain;
982 SoundRadius = prim.SoundRadius;
983 Text = prim.Text;
984 TextColor = prim.TextColor;
985 MediaURL = prim.MediaURL;
986 Joint = prim.Joint;
987 JointPivot = prim.JointPivot;
988 JointAxisOrAnchor = prim.JointAxisOrAnchor;
989 if (prim.NameValues != null)
990 {
991 if (NameValues == null || NameValues.Length != prim.NameValues.Length)
992 NameValues = new NameValue[prim.NameValues.Length];
993 Array.Copy(prim.NameValues, NameValues, prim.NameValues.Length);
994 }
995 else
996 NameValues = null;
997 PrimData = prim.PrimData;
998 Properties = prim.Properties;
999 // FIXME: Get a real copy constructor for TextureEntry instead of serializing to bytes and back
1000 if (prim.Textures != null)
1001 {
1002 byte[] textureBytes = prim.Textures.GetBytes();
1003 Textures = new TextureEntry(textureBytes, 0, textureBytes.Length);
1004 }
1005 else
1006 {
1007 Textures = null;
1008 }
1009 TextureAnim = prim.TextureAnim;
1010 ParticleSys = prim.ParticleSys;
1011 }
1012  
1013 #endregion Constructors
1014  
1015 #region Public Methods
1016  
1017 public virtual OSD GetOSD()
1018 {
1019 OSDMap path = new OSDMap(14);
1020 path["begin"] = OSD.FromReal(PrimData.PathBegin);
1021 path["curve"] = OSD.FromInteger((int)PrimData.PathCurve);
1022 path["end"] = OSD.FromReal(PrimData.PathEnd);
1023 path["radius_offset"] = OSD.FromReal(PrimData.PathRadiusOffset);
1024 path["revolutions"] = OSD.FromReal(PrimData.PathRevolutions);
1025 path["scale_x"] = OSD.FromReal(PrimData.PathScaleX);
1026 path["scale_y"] = OSD.FromReal(PrimData.PathScaleY);
1027 path["shear_x"] = OSD.FromReal(PrimData.PathShearX);
1028 path["shear_y"] = OSD.FromReal(PrimData.PathShearY);
1029 path["skew"] = OSD.FromReal(PrimData.PathSkew);
1030 path["taper_x"] = OSD.FromReal(PrimData.PathTaperX);
1031 path["taper_y"] = OSD.FromReal(PrimData.PathTaperY);
1032 path["twist"] = OSD.FromReal(PrimData.PathTwist);
1033 path["twist_begin"] = OSD.FromReal(PrimData.PathTwistBegin);
1034  
1035 OSDMap profile = new OSDMap(4);
1036 profile["begin"] = OSD.FromReal(PrimData.ProfileBegin);
1037 profile["curve"] = OSD.FromInteger((int)PrimData.ProfileCurve);
1038 profile["hole"] = OSD.FromInteger((int)PrimData.ProfileHole);
1039 profile["end"] = OSD.FromReal(PrimData.ProfileEnd);
1040 profile["hollow"] = OSD.FromReal(PrimData.ProfileHollow);
1041  
1042 OSDMap volume = new OSDMap(2);
1043 volume["path"] = path;
1044 volume["profile"] = profile;
1045  
1046 OSDMap prim = new OSDMap(20);
1047 if (Properties != null)
1048 {
1049 prim["name"] = OSD.FromString(Properties.Name);
1050 prim["description"] = OSD.FromString(Properties.Description);
1051 }
1052 else
1053 {
1054 prim["name"] = OSD.FromString("Object");
1055 prim["description"] = OSD.FromString(String.Empty);
1056 }
1057  
1058 prim["phantom"] = OSD.FromBoolean(((Flags & PrimFlags.Phantom) != 0));
1059 prim["physical"] = OSD.FromBoolean(((Flags & PrimFlags.Physics) != 0));
1060 prim["position"] = OSD.FromVector3(Position);
1061 prim["rotation"] = OSD.FromQuaternion(Rotation);
1062 prim["scale"] = OSD.FromVector3(Scale);
1063 prim["pcode"] = OSD.FromInteger((int)PrimData.PCode);
1064 prim["material"] = OSD.FromInteger((int)PrimData.Material);
1065 prim["shadows"] = OSD.FromBoolean(((Flags & PrimFlags.CastShadows) != 0));
1066 prim["state"] = OSD.FromInteger(PrimData.State);
1067  
1068 prim["id"] = OSD.FromUUID(ID);
1069 prim["localid"] = OSD.FromUInteger(LocalID);
1070 prim["parentid"] = OSD.FromUInteger(ParentID);
1071  
1072 prim["volume"] = volume;
1073  
1074 if (Textures != null)
1075 prim["textures"] = Textures.GetOSD();
1076  
1077 if ((TextureAnim.Flags & TextureAnimMode.ANIM_ON) != 0)
1078 prim["texture_anim"] = TextureAnim.GetOSD();
1079  
1080 if (Light != null)
1081 prim["light"] = Light.GetOSD();
1082  
1083 if (LightMap != null)
1084 prim["light_image"] = LightMap.GetOSD();
1085  
1086 if (Flexible != null)
1087 prim["flex"] = Flexible.GetOSD();
1088  
1089 if (Sculpt != null)
1090 prim["sculpt"] = Sculpt.GetOSD();
1091  
1092 return prim;
1093 }
1094  
1095 public static Primitive FromOSD(OSD osd)
1096 {
1097 Primitive prim = new Primitive();
1098 Primitive.ConstructionData data;
1099  
1100 OSDMap map = (OSDMap)osd;
1101 OSDMap volume = (OSDMap)map["volume"];
1102 OSDMap path = (OSDMap)volume["path"];
1103 OSDMap profile = (OSDMap)volume["profile"];
1104  
1105 #region Path/Profile
1106  
1107 data.profileCurve = (byte)0;
1108 data.Material = (Material)map["material"].AsInteger();
1109 data.PCode = (PCode)map["pcode"].AsInteger();
1110 data.State = (byte)map["state"].AsInteger();
1111  
1112 data.PathBegin = (float)path["begin"].AsReal();
1113 data.PathCurve = (PathCurve)path["curve"].AsInteger();
1114 data.PathEnd = (float)path["end"].AsReal();
1115 data.PathRadiusOffset = (float)path["radius_offset"].AsReal();
1116 data.PathRevolutions = (float)path["revolutions"].AsReal();
1117 data.PathScaleX = (float)path["scale_x"].AsReal();
1118 data.PathScaleY = (float)path["scale_y"].AsReal();
1119 data.PathShearX = (float)path["shear_x"].AsReal();
1120 data.PathShearY = (float)path["shear_y"].AsReal();
1121 data.PathSkew = (float)path["skew"].AsReal();
1122 data.PathTaperX = (float)path["taper_x"].AsReal();
1123 data.PathTaperY = (float)path["taper_y"].AsReal();
1124 data.PathTwist = (float)path["twist"].AsReal();
1125 data.PathTwistBegin = (float)path["twist_begin"].AsReal();
1126  
1127 data.ProfileBegin = (float)profile["begin"].AsReal();
1128 data.ProfileEnd = (float)profile["end"].AsReal();
1129 data.ProfileHollow = (float)profile["hollow"].AsReal();
1130 data.ProfileCurve = (ProfileCurve)profile["curve"].AsInteger();
1131 data.ProfileHole = (HoleType)profile["hole"].AsInteger();
1132  
1133 #endregion Path/Profile
1134  
1135 prim.PrimData = data;
1136  
1137 if (map["phantom"].AsBoolean())
1138 prim.Flags |= PrimFlags.Phantom;
1139  
1140 if (map["physical"].AsBoolean())
1141 prim.Flags |= PrimFlags.Physics;
1142  
1143 if (map["shadows"].AsBoolean())
1144 prim.Flags |= PrimFlags.CastShadows;
1145  
1146 prim.ID = map["id"].AsUUID();
1147 prim.LocalID = map["localid"].AsUInteger();
1148 prim.ParentID = map["parentid"].AsUInteger();
1149 prim.Position = ((OSDArray)map["position"]).AsVector3();
1150 prim.Rotation = ((OSDArray)map["rotation"]).AsQuaternion();
1151 prim.Scale = ((OSDArray)map["scale"]).AsVector3();
1152  
1153 if (map["flex"])
1154 prim.Flexible = FlexibleData.FromOSD(map["flex"]);
1155  
1156 if (map["light"])
1157 prim.Light = LightData.FromOSD(map["light"]);
1158  
1159 if (map["light_image"])
1160 prim.LightMap = LightImage.FromOSD(map["light_image"]);
1161  
1162 if (map["sculpt"])
1163 prim.Sculpt = SculptData.FromOSD(map["sculpt"]);
1164  
1165 prim.Textures = TextureEntry.FromOSD(map["textures"]);
1166  
1167 if (map["texture_anim"])
1168 prim.TextureAnim = TextureAnimation.FromOSD(map["texture_anim"]);
1169  
1170 prim.Properties = new ObjectProperties();
1171  
1172 if (!string.IsNullOrEmpty(map["name"].AsString()))
1173 {
1174 prim.Properties.Name = map["name"].AsString();
1175 }
1176  
1177 if (!string.IsNullOrEmpty(map["description"].AsString()))
1178 {
1179 prim.Properties.Description = map["description"].AsString();
1180 }
1181  
1182 return prim;
1183 }
1184  
1185 public int SetExtraParamsFromBytes(byte[] data, int pos)
1186 {
1187 int i = pos;
1188 int totalLength = 1;
1189  
1190 if (data.Length == 0 || pos >= data.Length)
1191 return 0;
1192  
1193 byte extraParamCount = data[i++];
1194  
1195 for (int k = 0; k < extraParamCount; k++)
1196 {
1197 ExtraParamType type = (ExtraParamType)Utils.BytesToUInt16(data, i);
1198 i += 2;
1199  
1200 uint paramLength = Utils.BytesToUInt(data, i);
1201 i += 4;
1202  
1203 if (type == ExtraParamType.Flexible)
1204 Flexible = new FlexibleData(data, i);
1205 else if (type == ExtraParamType.Light)
1206 Light = new LightData(data, i);
1207 else if (type == ExtraParamType.LightImage)
1208 LightMap = new LightImage(data, i);
1209 else if (type == ExtraParamType.Sculpt || type == ExtraParamType.Mesh)
1210 Sculpt = new SculptData(data, i);
1211  
1212 i += (int)paramLength;
1213 totalLength += (int)paramLength + 6;
1214 }
1215  
1216 return totalLength;
1217 }
1218  
1219 public byte[] GetExtraParamsBytes()
1220 {
1221 byte[] flexible = null;
1222 byte[] light = null;
1223 byte[] lightmap = null;
1224 byte[] sculpt = null;
1225 byte[] buffer = null;
1226 int size = 1;
1227 int pos = 0;
1228 byte count = 0;
1229  
1230 if (Flexible != null)
1231 {
1232 flexible = Flexible.GetBytes();
1233 size += flexible.Length + 6;
1234 ++count;
1235 }
1236 if (Light != null)
1237 {
1238 light = Light.GetBytes();
1239 size += light.Length + 6;
1240 ++count;
1241 }
1242 if (LightMap != null)
1243 {
1244 lightmap = LightMap.GetBytes();
1245 size += lightmap.Length + 6;
1246 ++count;
1247 }
1248 if (Sculpt != null)
1249 {
1250 sculpt = Sculpt.GetBytes();
1251 size += sculpt.Length + 6;
1252 ++count;
1253 }
1254  
1255 buffer = new byte[size];
1256 buffer[0] = count;
1257 ++pos;
1258  
1259 if (flexible != null)
1260 {
1261 Buffer.BlockCopy(Utils.UInt16ToBytes((ushort)ExtraParamType.Flexible), 0, buffer, pos, 2);
1262 pos += 2;
1263  
1264 Buffer.BlockCopy(Utils.UIntToBytes((uint)flexible.Length), 0, buffer, pos, 4);
1265 pos += 4;
1266  
1267 Buffer.BlockCopy(flexible, 0, buffer, pos, flexible.Length);
1268 pos += flexible.Length;
1269 }
1270 if (light != null)
1271 {
1272 Buffer.BlockCopy(Utils.UInt16ToBytes((ushort)ExtraParamType.Light), 0, buffer, pos, 2);
1273 pos += 2;
1274  
1275 Buffer.BlockCopy(Utils.UIntToBytes((uint)light.Length), 0, buffer, pos, 4);
1276 pos += 4;
1277  
1278 Buffer.BlockCopy(light, 0, buffer, pos, light.Length);
1279 pos += light.Length;
1280 }
1281 if (lightmap != null)
1282 {
1283 Buffer.BlockCopy(Utils.UInt16ToBytes((ushort)ExtraParamType.LightImage), 0, buffer, pos, 2);
1284 pos += 2;
1285  
1286 Buffer.BlockCopy(Utils.UIntToBytes((uint)lightmap.Length), 0, buffer, pos, 4);
1287 pos += 4;
1288  
1289 Buffer.BlockCopy(lightmap, 0, buffer, pos, lightmap.Length);
1290 pos += lightmap.Length;
1291 }
1292 if (sculpt != null)
1293 {
1294 if (Sculpt.Type == SculptType.Mesh)
1295 {
1296 Buffer.BlockCopy(Utils.UInt16ToBytes((ushort)ExtraParamType.Mesh), 0, buffer, pos, 2);
1297 }
1298 else
1299 {
1300 Buffer.BlockCopy(Utils.UInt16ToBytes((ushort)ExtraParamType.Sculpt), 0, buffer, pos, 2);
1301 }
1302 pos += 2;
1303  
1304 Buffer.BlockCopy(Utils.UIntToBytes((uint)sculpt.Length), 0, buffer, pos, 4);
1305 pos += 4;
1306  
1307 Buffer.BlockCopy(sculpt, 0, buffer, pos, sculpt.Length);
1308 pos += sculpt.Length;
1309 }
1310  
1311 return buffer;
1312 }
1313  
1314 #endregion Public Methods
1315  
1316 #region Overrides
1317  
1318 public override bool Equals(object obj)
1319 {
1320 return (obj is Primitive) ? this == (Primitive)obj : false;
1321 }
1322  
1323 public bool Equals(Primitive other)
1324 {
1325 return this == other;
1326 }
1327  
1328 public override string ToString()
1329 {
1330 switch (PrimData.PCode)
1331 {
1332 case PCode.Prim:
1333 return String.Format("{0} ({1})", Type, ID);
1334 default:
1335 return String.Format("{0} ({1})", PrimData.PCode, ID);
1336 }
1337 }
1338  
1339 public override int GetHashCode()
1340 {
1341 return
1342 Position.GetHashCode() ^
1343 Velocity.GetHashCode() ^
1344 Acceleration.GetHashCode() ^
1345 Rotation.GetHashCode() ^
1346 AngularVelocity.GetHashCode() ^
1347 ClickAction.GetHashCode() ^
1348 (Flexible != null ? Flexible.GetHashCode() : 0) ^
1349 (Light != null ? Light.GetHashCode() : 0) ^
1350 (Sculpt != null ? Sculpt.GetHashCode() : 0) ^
1351 Flags.GetHashCode() ^
1352 PrimData.Material.GetHashCode() ^
1353 MediaURL.GetHashCode() ^
1354 //TODO: NameValues?
1355 (Properties != null ? Properties.OwnerID.GetHashCode() : 0) ^
1356 ParentID.GetHashCode() ^
1357 PrimData.PathBegin.GetHashCode() ^
1358 PrimData.PathCurve.GetHashCode() ^
1359 PrimData.PathEnd.GetHashCode() ^
1360 PrimData.PathRadiusOffset.GetHashCode() ^
1361 PrimData.PathRevolutions.GetHashCode() ^
1362 PrimData.PathScaleX.GetHashCode() ^
1363 PrimData.PathScaleY.GetHashCode() ^
1364 PrimData.PathShearX.GetHashCode() ^
1365 PrimData.PathShearY.GetHashCode() ^
1366 PrimData.PathSkew.GetHashCode() ^
1367 PrimData.PathTaperX.GetHashCode() ^
1368 PrimData.PathTaperY.GetHashCode() ^
1369 PrimData.PathTwist.GetHashCode() ^
1370 PrimData.PathTwistBegin.GetHashCode() ^
1371 PrimData.PCode.GetHashCode() ^
1372 PrimData.ProfileBegin.GetHashCode() ^
1373 PrimData.ProfileCurve.GetHashCode() ^
1374 PrimData.ProfileEnd.GetHashCode() ^
1375 PrimData.ProfileHollow.GetHashCode() ^
1376 ParticleSys.GetHashCode() ^
1377 TextColor.GetHashCode() ^
1378 TextureAnim.GetHashCode() ^
1379 (Textures != null ? Textures.GetHashCode() : 0) ^
1380 SoundRadius.GetHashCode() ^
1381 Scale.GetHashCode() ^
1382 Sound.GetHashCode() ^
1383 PrimData.State.GetHashCode() ^
1384 Text.GetHashCode() ^
1385 TreeSpecies.GetHashCode();
1386 }
1387  
1388 #endregion Overrides
1389  
1390 #region Operators
1391  
1392 public static bool operator ==(Primitive lhs, Primitive rhs)
1393 {
1394 if ((Object)lhs == null || (Object)rhs == null)
1395 {
1396 return (Object)rhs == (Object)lhs;
1397 }
1398 return (lhs.ID == rhs.ID);
1399 }
1400  
1401 public static bool operator !=(Primitive lhs, Primitive rhs)
1402 {
1403 if ((Object)lhs == null || (Object)rhs == null)
1404 {
1405 return (Object)rhs != (Object)lhs;
1406 }
1407 return !(lhs.ID == rhs.ID);
1408 }
1409  
1410 #endregion Operators
1411  
1412 #region Parameter Packing Methods
1413  
1414 public static ushort PackBeginCut(float beginCut)
1415 {
1416 return (ushort)Math.Round(beginCut / CUT_QUANTA);
1417 }
1418  
1419 public static ushort PackEndCut(float endCut)
1420 {
1421 return (ushort)(50000 - (ushort)Math.Round(endCut / CUT_QUANTA));
1422 }
1423  
1424 public static byte PackPathScale(float pathScale)
1425 {
1426 return (byte)(200 - (byte)Math.Round(pathScale / SCALE_QUANTA));
1427 }
1428  
1429 public static sbyte PackPathShear(float pathShear)
1430 {
1431 return (sbyte)Math.Round(pathShear / SHEAR_QUANTA);
1432 }
1433  
1434 /// <summary>
1435 /// Packs PathTwist, PathTwistBegin, PathRadiusOffset, and PathSkew
1436 /// parameters in to signed eight bit values
1437 /// </summary>
1438 /// <param name="pathTwist">Floating point parameter to pack</param>
1439 /// <returns>Signed eight bit value containing the packed parameter</returns>
1440 public static sbyte PackPathTwist(float pathTwist)
1441 {
1442 return (sbyte)Math.Round(pathTwist / SCALE_QUANTA);
1443 }
1444  
1445 public static sbyte PackPathTaper(float pathTaper)
1446 {
1447 return (sbyte)Math.Round(pathTaper / TAPER_QUANTA);
1448 }
1449  
1450 public static byte PackPathRevolutions(float pathRevolutions)
1451 {
1452 return (byte)Math.Round((pathRevolutions - 1f) / REV_QUANTA);
1453 }
1454  
1455 public static ushort PackProfileHollow(float profileHollow)
1456 {
1457 return (ushort)Math.Round(profileHollow / HOLLOW_QUANTA);
1458 }
1459  
1460 #endregion Parameter Packing Methods
1461  
1462 #region Parameter Unpacking Methods
1463  
1464 public static float UnpackBeginCut(ushort beginCut)
1465 {
1466 return (float)beginCut * CUT_QUANTA;
1467 }
1468  
1469 public static float UnpackEndCut(ushort endCut)
1470 {
1471 return (float)(50000 - endCut) * CUT_QUANTA;
1472 }
1473  
1474 public static float UnpackPathScale(byte pathScale)
1475 {
1476 return (float)(200 - pathScale) * SCALE_QUANTA;
1477 }
1478  
1479 public static float UnpackPathShear(sbyte pathShear)
1480 {
1481 return (float)pathShear * SHEAR_QUANTA;
1482 }
1483  
1484 /// <summary>
1485 /// Unpacks PathTwist, PathTwistBegin, PathRadiusOffset, and PathSkew
1486 /// parameters from signed eight bit integers to floating point values
1487 /// </summary>
1488 /// <param name="pathTwist">Signed eight bit value to unpack</param>
1489 /// <returns>Unpacked floating point value</returns>
1490 public static float UnpackPathTwist(sbyte pathTwist)
1491 {
1492 return (float)pathTwist * SCALE_QUANTA;
1493 }
1494  
1495 public static float UnpackPathTaper(sbyte pathTaper)
1496 {
1497 return (float)pathTaper * TAPER_QUANTA;
1498 }
1499  
1500 public static float UnpackPathRevolutions(byte pathRevolutions)
1501 {
1502 return (float)pathRevolutions * REV_QUANTA + 1f;
1503 }
1504  
1505 public static float UnpackProfileHollow(ushort profileHollow)
1506 {
1507 return (float)profileHollow * HOLLOW_QUANTA;
1508 }
1509  
1510 #endregion Parameter Unpacking Methods
1511 }
1512 }