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 System.IO;
30 using OpenMetaverse.StructuredData;
31  
32 namespace OpenMetaverse
33 {
34 #region Enumerations
35  
36 /// <summary>
37 /// The type of bump-mapping applied to a face
38 /// </summary>
39 public enum Bumpiness : byte
40 {
41 /// <summary></summary>
42 None = 0,
43 /// <summary></summary>
44 Brightness = 1,
45 /// <summary></summary>
46 Darkness = 2,
47 /// <summary></summary>
48 Woodgrain = 3,
49 /// <summary></summary>
50 Bark = 4,
51 /// <summary></summary>
52 Bricks = 5,
53 /// <summary></summary>
54 Checker = 6,
55 /// <summary></summary>
56 Concrete = 7,
57 /// <summary></summary>
58 Crustytile = 8,
59 /// <summary></summary>
60 Cutstone = 9,
61 /// <summary></summary>
62 Discs = 10,
63 /// <summary></summary>
64 Gravel = 11,
65 /// <summary></summary>
66 Petridish = 12,
67 /// <summary></summary>
68 Siding = 13,
69 /// <summary></summary>
70 Stonetile = 14,
71 /// <summary></summary>
72 Stucco = 15,
73 /// <summary></summary>
74 Suction = 16,
75 /// <summary></summary>
76 Weave = 17
77 }
78  
79 /// <summary>
80 /// The level of shininess applied to a face
81 /// </summary>
82 public enum Shininess : byte
83 {
84 /// <summary></summary>
85 None = 0,
86 /// <summary></summary>
87 Low = 0x40,
88 /// <summary></summary>
89 Medium = 0x80,
90 /// <summary></summary>
91 High = 0xC0
92 }
93  
94 /// <summary>
95 /// The texture mapping style used for a face
96 /// </summary>
97 public enum MappingType : byte
98 {
99 /// <summary></summary>
100 Default = 0,
101 /// <summary></summary>
102 Planar = 2,
103 /// <summary></summary>
104 Spherical = 4,
105 /// <summary></summary>
106 Cylindrical = 6
107 }
108  
109 /// <summary>
110 /// Flags in the TextureEntry block that describe which properties are
111 /// set
112 /// </summary>
113 [Flags]
114 public enum TextureAttributes : uint
115 {
116 /// <summary></summary>
117 None = 0,
118 /// <summary></summary>
119 TextureID = 1 << 0,
120 /// <summary></summary>
121 RGBA = 1 << 1,
122 /// <summary></summary>
123 RepeatU = 1 << 2,
124 /// <summary></summary>
125 RepeatV = 1 << 3,
126 /// <summary></summary>
127 OffsetU = 1 << 4,
128 /// <summary></summary>
129 OffsetV = 1 << 5,
130 /// <summary></summary>
131 Rotation = 1 << 6,
132 /// <summary></summary>
133 Material = 1 << 7,
134 /// <summary></summary>
135 Media = 1 << 8,
136 /// <summary></summary>
137 Glow = 1 << 9,
138 /// <summary></summary>
139 MaterialID = 1 << 10,
140 /// <summary></summary>
141 All = 0xFFFFFFFF
142 }
143  
144 #endregion Enumerations
145  
146 public partial class Primitive
147 {
148 #region Enums
149  
150 /// <summary>
151 /// Texture animation mode
152 /// </summary>
153 [Flags]
154 public enum TextureAnimMode : uint
155 {
156 /// <summary>Disable texture animation</summary>
157 ANIM_OFF = 0x00,
158 /// <summary>Enable texture animation</summary>
159 ANIM_ON = 0x01,
160 /// <summary>Loop when animating textures</summary>
161 LOOP = 0x02,
162 /// <summary>Animate in reverse direction</summary>
163 REVERSE = 0x04,
164 /// <summary>Animate forward then reverse</summary>
165 PING_PONG = 0x08,
166 /// <summary>Slide texture smoothly instead of frame-stepping</summary>
167 SMOOTH = 0x10,
168 /// <summary>Rotate texture instead of using frames</summary>
169 ROTATE = 0x20,
170 /// <summary>Scale texture instead of using frames</summary>
171 SCALE = 0x40,
172 }
173  
174 #endregion Enums
175  
176 #region Subclasses
177  
178 /// <summary>
179 /// A single textured face. Don't instantiate this class yourself, use the
180 /// methods in TextureEntry
181 /// </summary>
182 public class TextureEntryFace : ICloneable
183 {
184 // +----------+ S = Shiny
185 // | SSFBBBBB | F = Fullbright
186 // | 76543210 | B = Bumpmap
187 // +----------+
188 private const byte BUMP_MASK = 0x1F;
189 private const byte FULLBRIGHT_MASK = 0x20;
190 private const byte SHINY_MASK = 0xC0;
191 // +----------+ M = Media Flags (web page)
192 // | .....TTM | T = Texture Mapping
193 // | 76543210 | . = Unused
194 // +----------+
195 private const byte MEDIA_MASK = 0x01;
196 private const byte TEX_MAP_MASK = 0x06;
197  
198 private Color4 rgba;
199 private float repeatU;
200 private float repeatV;
201 private float offsetU;
202 private float offsetV;
203 private float rotation;
204 private float glow;
205 private byte materialb;
206 private byte mediab;
207 private TextureAttributes hasAttribute;
208 private UUID textureID;
209 private UUID materialID;
210 private TextureEntryFace DefaultTexture;
211  
212  
213 #region Properties
214  
215 /// <summary></summary>
216 internal byte material
217 {
218 get
219 {
220 if ((hasAttribute & TextureAttributes.Material) != 0)
221 return materialb;
222 else
223 return DefaultTexture.material;
224 }
225 set
226 {
227 materialb = value;
228 hasAttribute |= TextureAttributes.Material;
229 }
230 }
231  
232 /// <summary></summary>
233 internal byte media
234 {
235 get
236 {
237 if ((hasAttribute & TextureAttributes.Media) != 0)
238 return mediab;
239 else
240 return DefaultTexture.media;
241 }
242 set
243 {
244 mediab = value;
245 hasAttribute |= TextureAttributes.Media;
246 }
247 }
248  
249 /// <summary></summary>
250 public Color4 RGBA
251 {
252 get
253 {
254 if ((hasAttribute & TextureAttributes.RGBA) != 0)
255 return rgba;
256 else
257 return DefaultTexture.rgba;
258 }
259 set
260 {
261 rgba = value;
262 hasAttribute |= TextureAttributes.RGBA;
263 }
264 }
265  
266 /// <summary></summary>
267 public float RepeatU
268 {
269 get
270 {
271 if ((hasAttribute & TextureAttributes.RepeatU) != 0)
272 return repeatU;
273 else
274 return DefaultTexture.repeatU;
275 }
276 set
277 {
278 repeatU = value;
279 hasAttribute |= TextureAttributes.RepeatU;
280 }
281 }
282  
283 /// <summary></summary>
284 public float RepeatV
285 {
286 get
287 {
288 if ((hasAttribute & TextureAttributes.RepeatV) != 0)
289 return repeatV;
290 else
291 return DefaultTexture.repeatV;
292 }
293 set
294 {
295 repeatV = value;
296 hasAttribute |= TextureAttributes.RepeatV;
297 }
298 }
299  
300 /// <summary></summary>
301 public float OffsetU
302 {
303 get
304 {
305 if ((hasAttribute & TextureAttributes.OffsetU) != 0)
306 return offsetU;
307 else
308 return DefaultTexture.offsetU;
309 }
310 set
311 {
312 offsetU = value;
313 hasAttribute |= TextureAttributes.OffsetU;
314 }
315 }
316  
317 /// <summary></summary>
318 public float OffsetV
319 {
320 get
321 {
322 if ((hasAttribute & TextureAttributes.OffsetV) != 0)
323 return offsetV;
324 else
325 return DefaultTexture.offsetV;
326 }
327 set
328 {
329 offsetV = value;
330 hasAttribute |= TextureAttributes.OffsetV;
331 }
332 }
333  
334 /// <summary></summary>
335 public float Rotation
336 {
337 get
338 {
339 if ((hasAttribute & TextureAttributes.Rotation) != 0)
340 return rotation;
341 else
342 return DefaultTexture.rotation;
343 }
344 set
345 {
346 rotation = value;
347 hasAttribute |= TextureAttributes.Rotation;
348 }
349 }
350  
351 /// <summary></summary>
352 public float Glow
353 {
354 get
355 {
356 if ((hasAttribute & TextureAttributes.Glow) != 0)
357 return glow;
358 else
359 return DefaultTexture.glow;
360 }
361 set
362 {
363 glow = value;
364 hasAttribute |= TextureAttributes.Glow;
365 }
366 }
367  
368 /// <summary></summary>
369 public Bumpiness Bump
370 {
371 get
372 {
373 if ((hasAttribute & TextureAttributes.Material) != 0)
374 return (Bumpiness)(material & BUMP_MASK);
375 else
376 return DefaultTexture.Bump;
377 }
378 set
379 {
380 // Clear out the old material value
381 material &= 0xE0;
382 // Put the new bump value in the material byte
383 material |= (byte)value;
384 hasAttribute |= TextureAttributes.Material;
385 }
386 }
387  
388 public Shininess Shiny
389 {
390 get
391 {
392 if ((hasAttribute & TextureAttributes.Material) != 0)
393 return (Shininess)(material & SHINY_MASK);
394 else
395 return DefaultTexture.Shiny;
396 }
397 set
398 {
399 // Clear out the old shiny value
400 material &= 0x3F;
401 // Put the new shiny value in the material byte
402 material |= (byte)value;
403 hasAttribute |= TextureAttributes.Material;
404 }
405 }
406  
407 public bool Fullbright
408 {
409 get
410 {
411 if ((hasAttribute & TextureAttributes.Material) != 0)
412 return (material & FULLBRIGHT_MASK) != 0;
413 else
414 return DefaultTexture.Fullbright;
415 }
416 set
417 {
418 // Clear out the old fullbright value
419 material &= 0xDF;
420 if (value)
421 {
422 material |= 0x20;
423 hasAttribute |= TextureAttributes.Material;
424 }
425 }
426 }
427  
428 /// <summary>In the future this will specify whether a webpage is
429 /// attached to this face</summary>
430 public bool MediaFlags
431 {
432 get
433 {
434 if ((hasAttribute & TextureAttributes.Media) != 0)
435 return (media & MEDIA_MASK) != 0;
436 else
437 return DefaultTexture.MediaFlags;
438 }
439 set
440 {
441 // Clear out the old mediaflags value
442 media &= 0xFE;
443 if (value)
444 {
445 media |= 0x01;
446 hasAttribute |= TextureAttributes.Media;
447 }
448 }
449 }
450  
451 public MappingType TexMapType
452 {
453 get
454 {
455 if ((hasAttribute & TextureAttributes.Media) != 0)
456 return (MappingType)(media & TEX_MAP_MASK);
457 else
458 return DefaultTexture.TexMapType;
459 }
460 set
461 {
462 // Clear out the old texmap value
463 media &= 0xF9;
464 // Put the new texmap value in the media byte
465 media |= (byte)value;
466 hasAttribute |= TextureAttributes.Media;
467 }
468 }
469  
470 /// <summary></summary>
471 public UUID TextureID
472 {
473 get
474 {
475 if ((hasAttribute & TextureAttributes.TextureID) != 0)
476 return textureID;
477 else
478 return DefaultTexture.textureID;
479 }
480 set
481 {
482 textureID = value;
483 hasAttribute |= TextureAttributes.TextureID;
484 }
485 }
486  
487 /// <summary></summary>
488 public UUID MaterialID
489 {
490 get
491 {
492 if ((hasAttribute & TextureAttributes.MaterialID) != 0)
493 return materialID;
494 else
495 return DefaultTexture.materialID;
496 }
497 set
498 {
499 materialID = value;
500 hasAttribute |= TextureAttributes.MaterialID;
501 }
502 }
503  
504 #endregion Properties
505  
506 /// <summary>
507 /// Contains the definition for individual faces
508 /// </summary>
509 /// <param name="defaultTexture"></param>
510 public TextureEntryFace(TextureEntryFace defaultTexture)
511 {
512 rgba = Color4.White;
513 repeatU = 1.0f;
514 repeatV = 1.0f;
515  
516 DefaultTexture = defaultTexture;
517 if (DefaultTexture == null)
518 hasAttribute = TextureAttributes.All;
519 else
520 hasAttribute = TextureAttributes.None;
521 }
522  
523 public OSD GetOSD(int faceNumber)
524 {
525 OSDMap tex = new OSDMap(10);
526 if (faceNumber >= 0) tex["face_number"] = OSD.FromInteger(faceNumber);
527 tex["colors"] = OSD.FromColor4(RGBA);
528 tex["scales"] = OSD.FromReal(RepeatU);
529 tex["scalet"] = OSD.FromReal(RepeatV);
530 tex["offsets"] = OSD.FromReal(OffsetU);
531 tex["offsett"] = OSD.FromReal(OffsetV);
532 tex["imagerot"] = OSD.FromReal(Rotation);
533 tex["bump"] = OSD.FromInteger((int)Bump);
534 tex["shiny"] = OSD.FromInteger((int)Shiny);
535 tex["fullbright"] = OSD.FromBoolean(Fullbright);
536 tex["media_flags"] = OSD.FromInteger(Convert.ToInt32(MediaFlags));
537 tex["mapping"] = OSD.FromInteger((int)TexMapType);
538 tex["glow"] = OSD.FromReal(Glow);
539  
540 if (TextureID != Primitive.TextureEntry.WHITE_TEXTURE)
541 tex["imageid"] = OSD.FromUUID(TextureID);
542 else
543 tex["imageid"] = OSD.FromUUID(UUID.Zero);
544  
545 tex["materialid"] = OSD.FromUUID(materialID);
546  
547 return tex;
548 }
549  
550 public static TextureEntryFace FromOSD(OSD osd, TextureEntryFace defaultFace, out int faceNumber)
551 {
552 OSDMap map = (OSDMap)osd;
553  
554 TextureEntryFace face = new TextureEntryFace(defaultFace);
555 faceNumber = (map.ContainsKey("face_number")) ? map["face_number"].AsInteger() : -1;
556 Color4 rgba = face.RGBA;
557 rgba = ((OSDArray)map["colors"]).AsColor4();
558 face.RGBA = rgba;
559 face.RepeatU = (float)map["scales"].AsReal();
560 face.RepeatV = (float)map["scalet"].AsReal();
561 face.OffsetU = (float)map["offsets"].AsReal();
562 face.OffsetV = (float)map["offsett"].AsReal();
563 face.Rotation = (float)map["imagerot"].AsReal();
564 face.Bump = (Bumpiness)map["bump"].AsInteger();
565 face.Shiny = (Shininess)map["shiny"].AsInteger();
566 face.Fullbright = map["fullbright"].AsBoolean();
567 face.MediaFlags = map["media_flags"].AsBoolean();
568 face.TexMapType = (MappingType)map["mapping"].AsInteger();
569 face.Glow = (float)map["glow"].AsReal();
570 face.TextureID = map["imageid"].AsUUID();
571 face.MaterialID = map["materialid"];
572 return face;
573 }
574  
575 public object Clone()
576 {
577 TextureEntryFace ret = new TextureEntryFace(this.DefaultTexture == null ? null : (TextureEntryFace)this.DefaultTexture.Clone());
578 ret.rgba = rgba;
579 ret.repeatU = repeatU;
580 ret.repeatV = repeatV;
581 ret.offsetU = offsetU;
582 ret.offsetV = offsetV;
583 ret.rotation = rotation;
584 ret.glow = glow;
585 ret.materialb = materialb;
586 ret.mediab = mediab;
587 ret.hasAttribute = hasAttribute;
588 ret.textureID = textureID;
589 ret.materialID = materialID;
590 return ret;
591 }
592  
593 public override int GetHashCode()
594 {
595 return
596 RGBA.GetHashCode() ^
597 RepeatU.GetHashCode() ^
598 RepeatV.GetHashCode() ^
599 OffsetU.GetHashCode() ^
600 OffsetV.GetHashCode() ^
601 Rotation.GetHashCode() ^
602 Glow.GetHashCode() ^
603 Bump.GetHashCode() ^
604 Shiny.GetHashCode() ^
605 Fullbright.GetHashCode() ^
606 MediaFlags.GetHashCode() ^
607 TexMapType.GetHashCode() ^
608 TextureID.GetHashCode() ^
609 MaterialID.GetHashCode();
610 }
611  
612 /// <summary>
613 ///
614 /// </summary>
615 /// <returns></returns>
616 public override string ToString()
617 {
618 return String.Format("Color: {0} RepeatU: {1} RepeatV: {2} OffsetU: {3} OffsetV: {4} " +
619 "Rotation: {5} Bump: {6} Shiny: {7} Fullbright: {8} Mapping: {9} Media: {10} Glow: {11} ID: {12} MaterialID: {13}",
620 RGBA, RepeatU, RepeatV, OffsetU, OffsetV, Rotation, Bump, Shiny, Fullbright, TexMapType,
621 MediaFlags, Glow, TextureID, MaterialID);
622 }
623 }
624  
625 /// <summary>
626 /// Represents all of the texturable faces for an object
627 /// </summary>
628 /// <remarks>Grid objects have infinite faces, with each face
629 /// using the properties of the default face unless set otherwise. So if
630 /// you have a TextureEntry with a default texture uuid of X, and face 18
631 /// has a texture UUID of Y, every face would be textured with X except for
632 /// face 18 that uses Y. In practice however, primitives utilize a maximum
633 /// of nine faces</remarks>
634 public class TextureEntry
635 {
636 public const int MAX_FACES = 32;
637 public static readonly UUID WHITE_TEXTURE = new UUID("5748decc-f629-461c-9a36-a35a221fe21f");
638  
639 /// <summary></summary>
640 public TextureEntryFace DefaultTexture;
641 /// <summary></summary>
642 public TextureEntryFace[] FaceTextures = new TextureEntryFace[MAX_FACES];
643  
644 /// <summary>
645 /// Constructor that takes a default texture UUID
646 /// </summary>
647 /// <param name="defaultTextureID">Texture UUID to use as the default texture</param>
648 public TextureEntry(UUID defaultTextureID)
649 {
650 DefaultTexture = new TextureEntryFace(null);
651 DefaultTexture.TextureID = defaultTextureID;
652 }
653  
654 /// <summary>
655 /// Constructor that takes a <code>TextureEntryFace</code> for the
656 /// default face
657 /// </summary>
658 /// <param name="defaultFace">Face to use as the default face</param>
659 public TextureEntry(TextureEntryFace defaultFace)
660 {
661 DefaultTexture = new TextureEntryFace(null);
662 DefaultTexture.Bump = defaultFace.Bump;
663 DefaultTexture.Fullbright = defaultFace.Fullbright;
664 DefaultTexture.MediaFlags = defaultFace.MediaFlags;
665 DefaultTexture.OffsetU = defaultFace.OffsetU;
666 DefaultTexture.OffsetV = defaultFace.OffsetV;
667 DefaultTexture.RepeatU = defaultFace.RepeatU;
668 DefaultTexture.RepeatV = defaultFace.RepeatV;
669 DefaultTexture.RGBA = defaultFace.RGBA;
670 DefaultTexture.Rotation = defaultFace.Rotation;
671 DefaultTexture.Glow = defaultFace.Glow;
672 DefaultTexture.Shiny = defaultFace.Shiny;
673 DefaultTexture.TexMapType = defaultFace.TexMapType;
674 DefaultTexture.TextureID = defaultFace.TextureID;
675 DefaultTexture.MaterialID = defaultFace.MaterialID;
676 }
677  
678 /// <summary>
679 /// Constructor that creates the TextureEntry class from a byte array
680 /// </summary>
681 /// <param name="data">Byte array containing the TextureEntry field</param>
682 /// <param name="pos">Starting position of the TextureEntry field in
683 /// the byte array</param>
684 /// <param name="length">Length of the TextureEntry field, in bytes</param>
685 public TextureEntry(byte[] data, int pos, int length)
686 {
687 FromBytes(data, pos, length);
688 }
689  
690 /// <summary>
691 /// This will either create a new face if a custom face for the given
692 /// index is not defined, or return the custom face for that index if
693 /// it already exists
694 /// </summary>
695 /// <param name="index">The index number of the face to create or
696 /// retrieve</param>
697 /// <returns>A TextureEntryFace containing all the properties for that
698 /// face</returns>
699 public TextureEntryFace CreateFace(uint index)
700 {
701 if (index >= MAX_FACES) throw new Exception(index + " is outside the range of MAX_FACES");
702  
703 if (FaceTextures[index] == null)
704 FaceTextures[index] = new TextureEntryFace(this.DefaultTexture);
705  
706 return FaceTextures[index];
707 }
708  
709 /// <summary>
710 ///
711 /// </summary>
712 /// <param name="index"></param>
713 /// <returns></returns>
714 public TextureEntryFace GetFace(uint index)
715 {
716 if (index >= MAX_FACES) throw new Exception(index + " is outside the range of MAX_FACES");
717  
718 if (FaceTextures[index] != null)
719 return FaceTextures[index];
720 else
721 return DefaultTexture;
722 }
723  
724 /// <summary>
725 ///
726 /// </summary>
727 /// <returns></returns>
728 public OSD GetOSD()
729 {
730 OSDArray array = new OSDArray();
731  
732 // If DefaultTexture is null, assume the whole TextureEntry is empty
733 if (DefaultTexture == null)
734 return array;
735  
736 // Otherwise, always add default texture
737 array.Add(DefaultTexture.GetOSD(-1));
738  
739 for (int i = 0; i < MAX_FACES; i++)
740 {
741 if (FaceTextures[i] != null)
742 array.Add(FaceTextures[i].GetOSD(i));
743 }
744  
745 return array;
746 }
747  
748 public static TextureEntry FromOSD(OSD osd)
749 {
750 if (osd.Type == OSDType.Array)
751 {
752 OSDArray array = (OSDArray)osd;
753 OSDMap faceSD;
754  
755 if (array.Count > 0)
756 {
757 int faceNumber;
758 faceSD = (OSDMap)array[0];
759 TextureEntryFace defaultFace = TextureEntryFace.FromOSD(faceSD, null, out faceNumber);
760 TextureEntry te = new TextureEntry(defaultFace);
761  
762 for (int i = 1; i < array.Count; i++)
763 {
764 TextureEntryFace tex = TextureEntryFace.FromOSD(array[i], defaultFace, out faceNumber);
765 if (faceNumber >= 0 && faceNumber < te.FaceTextures.Length)
766 te.FaceTextures[faceNumber] = tex;
767 }
768  
769 return te;
770 }
771 }
772  
773 return new TextureEntry(UUID.Zero);
774 }
775  
776 private void FromBytes(byte[] data, int pos, int length)
777 {
778 if (length < 16)
779 {
780 // No TextureEntry to process
781 DefaultTexture = null;
782 return;
783 }
784 else
785 {
786 DefaultTexture = new TextureEntryFace(null);
787 }
788  
789 uint bitfieldSize = 0;
790 uint faceBits = 0;
791 int i = pos;
792  
793 #region Texture
794 DefaultTexture.TextureID = new UUID(data, i);
795 i += 16;
796  
797 while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
798 {
799 UUID tmpUUID = new UUID(data, i);
800 i += 16;
801  
802 for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
803 if ((faceBits & bit) != 0)
804 CreateFace(face).TextureID = tmpUUID;
805 }
806 #endregion Texture
807  
808 #region Color
809 DefaultTexture.RGBA = new Color4(data, i, true);
810 i += 4;
811  
812 while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
813 {
814 Color4 tmpColor = new Color4(data, i, true);
815 i += 4;
816  
817 for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
818 if ((faceBits & bit) != 0)
819 CreateFace(face).RGBA = tmpColor;
820 }
821 #endregion Color
822  
823 #region RepeatU
824 DefaultTexture.RepeatU = Utils.BytesToFloat(data, i);
825 i += 4;
826  
827 while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
828 {
829 float tmpFloat = Utils.BytesToFloat(data, i);
830 i += 4;
831  
832 for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
833 if ((faceBits & bit) != 0)
834 CreateFace(face).RepeatU = tmpFloat;
835 }
836 #endregion RepeatU
837  
838 #region RepeatV
839 DefaultTexture.RepeatV = Utils.BytesToFloat(data, i);
840 i += 4;
841  
842 while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
843 {
844 float tmpFloat = Utils.BytesToFloat(data, i);
845 i += 4;
846  
847 for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
848 if ((faceBits & bit) != 0)
849 CreateFace(face).RepeatV = tmpFloat;
850 }
851 #endregion RepeatV
852  
853 #region OffsetU
854 DefaultTexture.OffsetU = Helpers.TEOffsetFloat(data, i);
855 i += 2;
856  
857 while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
858 {
859 float tmpFloat = Helpers.TEOffsetFloat(data, i);
860 i += 2;
861  
862 for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
863 if ((faceBits & bit) != 0)
864 CreateFace(face).OffsetU = tmpFloat;
865 }
866 #endregion OffsetU
867  
868 #region OffsetV
869 DefaultTexture.OffsetV = Helpers.TEOffsetFloat(data, i);
870 i += 2;
871  
872 while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
873 {
874 float tmpFloat = Helpers.TEOffsetFloat(data, i);
875 i += 2;
876  
877 for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
878 if ((faceBits & bit) != 0)
879 CreateFace(face).OffsetV = tmpFloat;
880 }
881 #endregion OffsetV
882  
883 #region Rotation
884 DefaultTexture.Rotation = Helpers.TERotationFloat(data, i);
885 i += 2;
886  
887 while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
888 {
889 float tmpFloat = Helpers.TERotationFloat(data, i);
890 i += 2;
891  
892 for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
893 if ((faceBits & bit) != 0)
894 CreateFace(face).Rotation = tmpFloat;
895 }
896 #endregion Rotation
897  
898 #region Material
899 DefaultTexture.material = data[i];
900 i++;
901  
902 while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
903 {
904 byte tmpByte = data[i];
905 i++;
906  
907 for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
908 if ((faceBits & bit) != 0)
909 CreateFace(face).material = tmpByte;
910 }
911 #endregion Material
912  
913 #region Media
914 DefaultTexture.media = data[i];
915 i++;
916  
917 while (i - pos < length && ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
918 {
919 byte tmpByte = data[i];
920 i++;
921  
922 for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
923 if ((faceBits & bit) != 0)
924 CreateFace(face).media = tmpByte;
925 }
926 #endregion Media
927  
928 #region Glow
929 DefaultTexture.Glow = Helpers.TEGlowFloat(data, i);
930 i++;
931  
932 while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
933 {
934 float tmpFloat = Helpers.TEGlowFloat(data, i);
935 i++;
936  
937 for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
938 if ((faceBits & bit) != 0)
939 CreateFace(face).Glow = tmpFloat;
940 }
941 #endregion Glow
942  
943 #region MaterialID
944 if (i - pos + 16 <= length)
945 {
946 DefaultTexture.MaterialID = new UUID(data, i);
947 i += 16;
948  
949 while (i - pos + 16 <= length && ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
950 {
951 UUID tmpUUID = new UUID(data, i);
952 i += 16;
953  
954 for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
955 if ((faceBits & bit) != 0)
956 CreateFace(face).MaterialID = tmpUUID;
957 }
958 }
959 #endregion MaterialID
960 }
961  
962 /// <summary>
963 ///
964 /// </summary>
965 /// <returns></returns>
966 public byte[] GetBytes()
967 {
968 if (DefaultTexture == null)
969 return Utils.EmptyBytes;
970  
971 using (MemoryStream memStream = new MemoryStream())
972 {
973 using (BinaryWriter binWriter = new BinaryWriter(memStream))
974 {
975 #region Bitfield Setup
976  
977 uint[] textures = new uint[FaceTextures.Length];
978 InitializeArray(ref textures);
979 uint[] rgbas = new uint[FaceTextures.Length];
980 InitializeArray(ref rgbas);
981 uint[] repeatus = new uint[FaceTextures.Length];
982 InitializeArray(ref repeatus);
983 uint[] repeatvs = new uint[FaceTextures.Length];
984 InitializeArray(ref repeatvs);
985 uint[] offsetus = new uint[FaceTextures.Length];
986 InitializeArray(ref offsetus);
987 uint[] offsetvs = new uint[FaceTextures.Length];
988 InitializeArray(ref offsetvs);
989 uint[] rotations = new uint[FaceTextures.Length];
990 InitializeArray(ref rotations);
991 uint[] materials = new uint[FaceTextures.Length];
992 InitializeArray(ref materials);
993 uint[] medias = new uint[FaceTextures.Length];
994 InitializeArray(ref medias);
995 uint[] glows = new uint[FaceTextures.Length];
996 InitializeArray(ref glows);
997 uint[] materialIDs = new uint[FaceTextures.Length];
998 InitializeArray(ref materialIDs);
999  
1000 for (int i = 0; i < FaceTextures.Length; i++)
1001 {
1002 if (FaceTextures[i] == null) continue;
1003  
1004 if (FaceTextures[i].TextureID != DefaultTexture.TextureID)
1005 {
1006 if (textures[i] == UInt32.MaxValue) textures[i] = 0;
1007 textures[i] |= (uint)(1 << i);
1008 }
1009 if (FaceTextures[i].RGBA != DefaultTexture.RGBA)
1010 {
1011 if (rgbas[i] == UInt32.MaxValue) rgbas[i] = 0;
1012 rgbas[i] |= (uint)(1 << i);
1013 }
1014 if (FaceTextures[i].RepeatU != DefaultTexture.RepeatU)
1015 {
1016 if (repeatus[i] == UInt32.MaxValue) repeatus[i] = 0;
1017 repeatus[i] |= (uint)(1 << i);
1018 }
1019 if (FaceTextures[i].RepeatV != DefaultTexture.RepeatV)
1020 {
1021 if (repeatvs[i] == UInt32.MaxValue) repeatvs[i] = 0;
1022 repeatvs[i] |= (uint)(1 << i);
1023 }
1024 if (Helpers.TEOffsetShort(FaceTextures[i].OffsetU) != Helpers.TEOffsetShort(DefaultTexture.OffsetU))
1025 {
1026 if (offsetus[i] == UInt32.MaxValue) offsetus[i] = 0;
1027 offsetus[i] |= (uint)(1 << i);
1028 }
1029 if (Helpers.TEOffsetShort(FaceTextures[i].OffsetV) != Helpers.TEOffsetShort(DefaultTexture.OffsetV))
1030 {
1031 if (offsetvs[i] == UInt32.MaxValue) offsetvs[i] = 0;
1032 offsetvs[i] |= (uint)(1 << i);
1033 }
1034 if (Helpers.TERotationShort(FaceTextures[i].Rotation) != Helpers.TERotationShort(DefaultTexture.Rotation))
1035 {
1036 if (rotations[i] == UInt32.MaxValue) rotations[i] = 0;
1037 rotations[i] |= (uint)(1 << i);
1038 }
1039 if (FaceTextures[i].material != DefaultTexture.material)
1040 {
1041 if (materials[i] == UInt32.MaxValue) materials[i] = 0;
1042 materials[i] |= (uint)(1 << i);
1043 }
1044 if (FaceTextures[i].media != DefaultTexture.media)
1045 {
1046 if (medias[i] == UInt32.MaxValue) medias[i] = 0;
1047 medias[i] |= (uint)(1 << i);
1048 }
1049 if (Helpers.TEGlowByte(FaceTextures[i].Glow) != Helpers.TEGlowByte(DefaultTexture.Glow))
1050 {
1051 if (glows[i] == UInt32.MaxValue) glows[i] = 0;
1052 glows[i] |= (uint)(1 << i);
1053 }
1054 if (FaceTextures[i].MaterialID != DefaultTexture.MaterialID)
1055 {
1056 if (materialIDs[i] == UInt32.MaxValue) materialIDs[i] = 0;
1057 materialIDs[i] |= (uint)(1 << i);
1058 }
1059 }
1060  
1061 #endregion Bitfield Setup
1062  
1063 #region Texture
1064 binWriter.Write(DefaultTexture.TextureID.GetBytes());
1065 for (int i = 0; i < textures.Length; i++)
1066 {
1067 if (textures[i] != UInt32.MaxValue)
1068 {
1069 binWriter.Write(GetFaceBitfieldBytes(textures[i]));
1070 binWriter.Write(FaceTextures[i].TextureID.GetBytes());
1071 }
1072 }
1073 binWriter.Write((byte)0);
1074 #endregion Texture
1075  
1076 #region Color
1077 // Serialize the color bytes inverted to optimize for zerocoding
1078 binWriter.Write(DefaultTexture.RGBA.GetBytes(true));
1079 for (int i = 0; i < rgbas.Length; i++)
1080 {
1081 if (rgbas[i] != UInt32.MaxValue)
1082 {
1083 binWriter.Write(GetFaceBitfieldBytes(rgbas[i]));
1084 // Serialize the color bytes inverted to optimize for zerocoding
1085 binWriter.Write(FaceTextures[i].RGBA.GetBytes(true));
1086 }
1087 }
1088 binWriter.Write((byte)0);
1089 #endregion Color
1090  
1091 #region RepeatU
1092 binWriter.Write(DefaultTexture.RepeatU);
1093 for (int i = 0; i < repeatus.Length; i++)
1094 {
1095 if (repeatus[i] != UInt32.MaxValue)
1096 {
1097 binWriter.Write(GetFaceBitfieldBytes(repeatus[i]));
1098 binWriter.Write(FaceTextures[i].RepeatU);
1099 }
1100 }
1101 binWriter.Write((byte)0);
1102 #endregion RepeatU
1103  
1104 #region RepeatV
1105 binWriter.Write(DefaultTexture.RepeatV);
1106 for (int i = 0; i < repeatvs.Length; i++)
1107 {
1108 if (repeatvs[i] != UInt32.MaxValue)
1109 {
1110 binWriter.Write(GetFaceBitfieldBytes(repeatvs[i]));
1111 binWriter.Write(FaceTextures[i].RepeatV);
1112 }
1113 }
1114 binWriter.Write((byte)0);
1115 #endregion RepeatV
1116  
1117 #region OffsetU
1118 binWriter.Write(Helpers.TEOffsetShort(DefaultTexture.OffsetU));
1119 for (int i = 0; i < offsetus.Length; i++)
1120 {
1121 if (offsetus[i] != UInt32.MaxValue)
1122 {
1123 binWriter.Write(GetFaceBitfieldBytes(offsetus[i]));
1124 binWriter.Write(Helpers.TEOffsetShort(FaceTextures[i].OffsetU));
1125 }
1126 }
1127 binWriter.Write((byte)0);
1128 #endregion OffsetU
1129  
1130 #region OffsetV
1131 binWriter.Write(Helpers.TEOffsetShort(DefaultTexture.OffsetV));
1132 for (int i = 0; i < offsetvs.Length; i++)
1133 {
1134 if (offsetvs[i] != UInt32.MaxValue)
1135 {
1136 binWriter.Write(GetFaceBitfieldBytes(offsetvs[i]));
1137 binWriter.Write(Helpers.TEOffsetShort(FaceTextures[i].OffsetV));
1138 }
1139 }
1140 binWriter.Write((byte)0);
1141 #endregion OffsetV
1142  
1143 #region Rotation
1144 binWriter.Write(Helpers.TERotationShort(DefaultTexture.Rotation));
1145 for (int i = 0; i < rotations.Length; i++)
1146 {
1147 if (rotations[i] != UInt32.MaxValue)
1148 {
1149 binWriter.Write(GetFaceBitfieldBytes(rotations[i]));
1150 binWriter.Write(Helpers.TERotationShort(FaceTextures[i].Rotation));
1151 }
1152 }
1153 binWriter.Write((byte)0);
1154 #endregion Rotation
1155  
1156 #region Material
1157 binWriter.Write(DefaultTexture.material);
1158 for (int i = 0; i < materials.Length; i++)
1159 {
1160 if (materials[i] != UInt32.MaxValue)
1161 {
1162 binWriter.Write(GetFaceBitfieldBytes(materials[i]));
1163 binWriter.Write(FaceTextures[i].material);
1164 }
1165 }
1166 binWriter.Write((byte)0);
1167 #endregion Material
1168  
1169 #region Media
1170 binWriter.Write(DefaultTexture.media);
1171 for (int i = 0; i < medias.Length; i++)
1172 {
1173 if (medias[i] != UInt32.MaxValue)
1174 {
1175 binWriter.Write(GetFaceBitfieldBytes(medias[i]));
1176 binWriter.Write(FaceTextures[i].media);
1177 }
1178 }
1179 binWriter.Write((byte)0);
1180 #endregion Media
1181  
1182 #region Glow
1183 binWriter.Write(Helpers.TEGlowByte(DefaultTexture.Glow));
1184 for (int i = 0; i < glows.Length; i++)
1185 {
1186 if (glows[i] != UInt32.MaxValue)
1187 {
1188 binWriter.Write(GetFaceBitfieldBytes(glows[i]));
1189 binWriter.Write(Helpers.TEGlowByte(FaceTextures[i].Glow));
1190 }
1191 }
1192 binWriter.Write((byte)0);
1193 #endregion Glow
1194  
1195 #region MaterialID
1196 binWriter.Write(DefaultTexture.MaterialID.GetBytes());
1197 for (int i = 0; i < materialIDs.Length; i++)
1198 {
1199 if (materialIDs[i] != UInt32.MaxValue)
1200 {
1201 binWriter.Write(GetFaceBitfieldBytes(materialIDs[i]));
1202 binWriter.Write(FaceTextures[i].MaterialID.GetBytes());
1203 }
1204 }
1205 #endregion MaterialID
1206  
1207 return memStream.ToArray();
1208 }
1209 }
1210 }
1211  
1212 public override int GetHashCode()
1213 {
1214 int hashCode = DefaultTexture != null ? DefaultTexture.GetHashCode() : 0;
1215 for (int i = 0; i < FaceTextures.Length; i++)
1216 {
1217 if (FaceTextures[i] != null)
1218 hashCode ^= FaceTextures[i].GetHashCode();
1219 }
1220 return hashCode;
1221 }
1222  
1223 /// <summary>
1224 ///
1225 /// </summary>
1226 /// <returns></returns>
1227 public override string ToString()
1228 {
1229 string output = String.Empty;
1230  
1231 output += "Default Face: " + DefaultTexture.ToString() + Environment.NewLine;
1232  
1233 for (int i = 0; i < FaceTextures.Length; i++)
1234 {
1235 if (FaceTextures[i] != null)
1236 output += "Face " + i + ": " + FaceTextures[i].ToString() + Environment.NewLine;
1237 }
1238  
1239 return output;
1240 }
1241  
1242 #region Helpers
1243  
1244 private void InitializeArray(ref uint[] array)
1245 {
1246 for (int i = 0; i < array.Length; i++)
1247 array[i] = UInt32.MaxValue;
1248 }
1249  
1250 private bool ReadFaceBitfield(byte[] data, ref int pos, ref uint faceBits, ref uint bitfieldSize)
1251 {
1252 faceBits = 0;
1253 bitfieldSize = 0;
1254  
1255 if (pos >= data.Length)
1256 return false;
1257  
1258 byte b = 0;
1259 do
1260 {
1261 b = data[pos];
1262 faceBits = (faceBits << 7) | (uint)(b & 0x7F);
1263 bitfieldSize += 7;
1264 pos++;
1265 }
1266 while ((b & 0x80) != 0);
1267  
1268 return (faceBits != 0);
1269 }
1270  
1271 private byte[] GetFaceBitfieldBytes(uint bitfield)
1272 {
1273 int byteLength = 0;
1274 uint tmpBitfield = bitfield;
1275 while (tmpBitfield != 0)
1276 {
1277 tmpBitfield >>= 7;
1278 byteLength++;
1279 }
1280  
1281 if (byteLength == 0)
1282 return new byte[1] { 0 };
1283  
1284 byte[] bytes = new byte[byteLength];
1285 for (int i = 0; i < byteLength; i++)
1286 {
1287 bytes[i] = (byte)((bitfield >> (7 * (byteLength - i - 1))) & 0x7F);
1288 if (i < byteLength - 1)
1289 bytes[i] |= 0x80;
1290 }
1291 return bytes;
1292 }
1293  
1294 #endregion Helpers
1295 }
1296  
1297 /// <summary>
1298 /// Controls the texture animation of a particular prim
1299 /// </summary>
1300 public struct TextureAnimation
1301 {
1302 /// <summary></summary>
1303 public TextureAnimMode Flags;
1304 /// <summary></summary>
1305 public uint Face;
1306 /// <summary></summary>
1307 public uint SizeX;
1308 /// <summary></summary>
1309 public uint SizeY;
1310 /// <summary></summary>
1311 public float Start;
1312 /// <summary></summary>
1313 public float Length;
1314 /// <summary></summary>
1315 public float Rate;
1316  
1317 /// <summary>
1318 ///
1319 /// </summary>
1320 /// <param name="data"></param>
1321 /// <param name="pos"></param>
1322 public TextureAnimation(byte[] data, int pos)
1323 {
1324 if (data.Length >= 16)
1325 {
1326 Flags = (TextureAnimMode)((uint)data[pos++]);
1327 Face = (uint)data[pos++];
1328 SizeX = (uint)data[pos++];
1329 SizeY = (uint)data[pos++];
1330  
1331 Start = Utils.BytesToFloat(data, pos);
1332 Length = Utils.BytesToFloat(data, pos + 4);
1333 Rate = Utils.BytesToFloat(data, pos + 8);
1334 }
1335 else
1336 {
1337 Flags = 0;
1338 Face = 0;
1339 SizeX = 0;
1340 SizeY = 0;
1341  
1342 Start = 0.0f;
1343 Length = 0.0f;
1344 Rate = 0.0f;
1345 }
1346 }
1347  
1348 /// <summary>
1349 ///
1350 /// </summary>
1351 /// <returns></returns>
1352 public byte[] GetBytes()
1353 {
1354 byte[] data = new byte[16];
1355 int pos = 0;
1356  
1357 data[pos++] = (byte)Flags;
1358 data[pos++] = (byte)Face;
1359 data[pos++] = (byte)SizeX;
1360 data[pos++] = (byte)SizeY;
1361  
1362 Utils.FloatToBytes(Start).CopyTo(data, pos);
1363 Utils.FloatToBytes(Length).CopyTo(data, pos + 4);
1364 Utils.FloatToBytes(Rate).CopyTo(data, pos + 4);
1365  
1366 return data;
1367 }
1368  
1369 public OSD GetOSD()
1370 {
1371 OSDMap map = new OSDMap();
1372  
1373 map["face"] = OSD.FromInteger(Face);
1374 map["flags"] = OSD.FromInteger((uint)Flags);
1375 map["length"] = OSD.FromReal(Length);
1376 map["rate"] = OSD.FromReal(Rate);
1377 map["size_x"] = OSD.FromInteger(SizeX);
1378 map["size_y"] = OSD.FromInteger(SizeY);
1379 map["start"] = OSD.FromReal(Start);
1380  
1381 return map;
1382 }
1383  
1384 public static TextureAnimation FromOSD(OSD osd)
1385 {
1386 TextureAnimation anim = new TextureAnimation();
1387 OSDMap map = osd as OSDMap;
1388  
1389 if (map != null)
1390 {
1391 anim.Face = map["face"].AsUInteger();
1392 anim.Flags = (TextureAnimMode)map["flags"].AsUInteger();
1393 anim.Length = (float)map["length"].AsReal();
1394 anim.Rate = (float)map["rate"].AsReal();
1395 anim.SizeX = map["size_x"].AsUInteger();
1396 anim.SizeY = map["size_y"].AsUInteger();
1397 anim.Start = (float)map["start"].AsReal();
1398 }
1399  
1400 return anim;
1401 }
1402 }
1403  
1404 #endregion Subclasses
1405  
1406 #region Public Members
1407  
1408 /// <summary></summary>
1409 public TextureEntry Textures;
1410 /// <summary></summary>
1411 public TextureAnimation TextureAnim;
1412  
1413 #endregion Public Members
1414 }
1415 }