corrade-vassal – Blame information for rev 1
?pathlinks?
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 | } |