OSDN Git Service

Merge pull request #23 from nooperation/ircplugin_update
[radegast/radegast.git] / Radegast / GUI / Rendering / RenderAvatar.cs
1 // 
2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2014, Radegast Development Team
4 // All rights reserved.
5 // 
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // 
9 //     * Redistributions of source code must retain the above copyright notice,
10 //       this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above copyright
12 //       notice, this list of conditions and the following disclaimer in the
13 //       documentation and/or other materials provided with the distribution.
14 //     * Neither the name of the application "Radegast", nor the names of its
15 //       contributors may be used to endorse or promote products derived from
16 //       this software without specific prior CreateReflectionTexture permission.
17 // 
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //
29 // $Id: RenderAvatar.cs 1137 2011-09-05 22:53:46Z latifer $
30 //
31
32 using System;
33 using System.Collections.Generic;
34 using System.Collections;
35 using System.IO;
36 using System.Xml;
37 #if (COGBOT_LIBOMV || USE_STHREADS)
38 using ThreadPoolUtil;
39 using Thread = ThreadPoolUtil.Thread;
40 using ThreadPool = ThreadPoolUtil.ThreadPool;
41 using Monitor = ThreadPoolUtil.Monitor;
42 #endif
43 using System.Threading;
44
45 using OpenMetaverse;
46 using OpenMetaverse.Rendering;
47
48 namespace Radegast.Rendering
49 {
50     public class attachment_point
51     {
52         public string name;
53         public string joint;
54         public Vector3 position;
55         public Quaternion rotation;
56         public int id;
57         public int group;
58
59         public GLMesh jointmesh;
60         public int jointmeshindex;
61
62         public attachment_point(XmlNode node)
63         {
64             name = node.Attributes.GetNamedItem("name").Value;
65             joint = node.Attributes.GetNamedItem("joint").Value;
66             position = VisualParamEx.XmlParseVector(node.Attributes.GetNamedItem("position").Value);
67             rotation = VisualParamEx.XmlParseRotation(node.Attributes.GetNamedItem("rotation").Value);
68             id = Int32.Parse(node.Attributes.GetNamedItem("id").Value);
69             group = Int32.Parse(node.Attributes.GetNamedItem("group").Value);
70         }
71
72     }
73
74     /// <summary>
75     /// Subclass of LindenMesh that adds vertex, index, and texture coordinate
76     /// arrays suitable for pushing direct to OpenGL
77     /// </summary>
78     public class GLMesh : LindenMesh
79     {
80         /// <summary>
81         /// Subclass of LODMesh that adds an index array suitable for pushing
82         /// direct to OpenGL
83         /// </summary>
84         /// 
85
86         public int teFaceID;
87         public Dictionary<int, VisualParamEx> _evp = new Dictionary<int, VisualParamEx>();
88
89         new public class LODMesh : LindenMesh.LODMesh
90         {
91             public ushort[] Indices;
92
93             public override void LoadMesh(string filename)
94             {
95                 base.LoadMesh(filename);
96
97                 // Generate the index array
98                 Indices = new ushort[_numFaces * 3];
99                 int current = 0;
100                 for (int i = 0; i < _numFaces; i++)
101                 {
102                     Indices[current++] = (ushort)_faces[i].Indices[0];
103                     Indices[current++] = (ushort)_faces[i].Indices[1];
104                     Indices[current++] = (ushort)_faces[i].Indices[2];
105                 }
106             }
107         }
108
109         /// <summary>
110         /// 
111         /// </summary>
112         public struct GLData
113         {
114             public float[] Vertices;
115             public float[] Normals;
116             public ushort[] Indices;
117             public float[] TexCoords;
118             public Vector3 Center;
119             public float[] weights; //strictly these are constant and don't need instancing with the GLMesh
120             public string[] skinJoints;  //strictly these are constant and don't need instancing with the GLMesh
121         }
122
123         public static GLData baseRenderData;
124         public GLData RenderData;
125         public GLData OrigRenderData;
126         public GLData MorphRenderData;
127
128         public GLAvatar av;
129
130         public GLMesh(string name)
131             : base(name)
132         {
133         }
134
135         public GLMesh(GLMesh source, GLAvatar av)
136             : base(source.Name)
137         {
138             this.av = av;
139             // Make a new GLMesh copy from the supplied source
140
141             RenderData.Vertices = new float[source.RenderData.Vertices.Length];
142             RenderData.Normals = new float[source.RenderData.Normals.Length];
143             RenderData.TexCoords = new float[source.RenderData.TexCoords.Length];
144             RenderData.Indices = new ushort[source.RenderData.Indices.Length];
145
146             RenderData.weights = new float[source.RenderData.weights.Length];
147             RenderData.skinJoints = new string[source.RenderData.skinJoints.Length];
148
149             Array.Copy(source.RenderData.Vertices, RenderData.Vertices, source.RenderData.Vertices.Length);
150             Array.Copy(source.RenderData.Normals, RenderData.Normals, source.RenderData.Normals.Length);
151
152             Array.Copy(source.RenderData.TexCoords, RenderData.TexCoords, source.RenderData.TexCoords.Length);
153             Array.Copy(source.RenderData.Indices, RenderData.Indices, source.RenderData.Indices.Length);
154             Array.Copy(source.RenderData.weights, RenderData.weights, source.RenderData.weights.Length);
155             Array.Copy(source.RenderData.skinJoints, RenderData.skinJoints, source.RenderData.skinJoints.Length);
156
157             RenderData.Center = new Vector3(source.RenderData.Center);
158
159             teFaceID = source.teFaceID;
160
161             RotationAngles = new Vector3(source.RotationAngles);
162             Scale = new Vector3(source.Scale);
163             Position = new Vector3(source.Position);
164
165             // We should not need to instance these the reference from the top should be constant
166             _evp = source._evp;
167             Morphs = source.Morphs;
168
169             OrigRenderData.Indices = new ushort[source.RenderData.Indices.Length];
170             OrigRenderData.TexCoords = new float[source.RenderData.TexCoords.Length];
171             OrigRenderData.Vertices = new float[source.RenderData.Vertices.Length];
172             OrigRenderData.Normals = new float[source.RenderData.Normals.Length];
173
174             MorphRenderData.Vertices = new float[source.RenderData.Vertices.Length];
175             MorphRenderData.Normals = new float[source.RenderData.Normals.Length];
176
177             Array.Copy(source.RenderData.Vertices, OrigRenderData.Vertices, source.RenderData.Vertices.Length);
178             Array.Copy(source.RenderData.Vertices, MorphRenderData.Vertices, source.RenderData.Vertices.Length);
179
180             Array.Copy(source.RenderData.Normals, OrigRenderData.Normals, source.RenderData.Normals.Length);
181             Array.Copy(source.RenderData.Normals, MorphRenderData.Normals, source.RenderData.Normals.Length);
182
183             Array.Copy(source.RenderData.TexCoords, OrigRenderData.TexCoords, source.RenderData.TexCoords.Length);
184             Array.Copy(source.RenderData.Indices, OrigRenderData.Indices, source.RenderData.Indices.Length);
185
186
187
188         }
189
190         public void setMeshPos(Vector3 pos)
191         {
192             Position = pos;
193
194             // Force offset all vertices by this offset
195             // this is required to force some meshes into the default T bind pose
196
197             for (int vert = 0; vert < RenderData.Vertices.Length; vert = vert + 3)
198             {
199                 RenderData.Vertices[vert] += pos.X;
200                 RenderData.Vertices[vert + 1] += pos.Y;
201                 RenderData.Vertices[vert + 2] += pos.Z;
202             }
203
204
205         }
206
207         public void setMeshRot(Vector3 rot)
208         {
209             RotationAngles = rot;
210         }
211
212         public override void LoadMesh(string filename)
213         {
214             base.LoadMesh(filename);
215
216             float minX, minY, minZ;
217             minX = minY = minZ = Single.MaxValue;
218             float maxX, maxY, maxZ;
219             maxX = maxY = maxZ = Single.MinValue;
220
221             // Generate the vertex array
222             RenderData.Vertices = new float[NumVertices * 3];
223             RenderData.Normals = new float[NumVertices * 3];
224
225             Quaternion quat = Quaternion.CreateFromEulers(0, 0, (float)(Math.PI / 4.0));
226
227             int current = 0;
228             for (int i = 0; i < NumVertices; i++)
229             {
230
231                 RenderData.Normals[current] = Vertices[i].Normal.X;
232                 RenderData.Vertices[current++] = Vertices[i].Coord.X;
233                 RenderData.Normals[current] = Vertices[i].Normal.Y;
234                 RenderData.Vertices[current++] = Vertices[i].Coord.Y;
235                 RenderData.Normals[current] = Vertices[i].Normal.Z;
236                 RenderData.Vertices[current++] = Vertices[i].Coord.Z;
237
238                 if (Vertices[i].Coord.X < minX)
239                     minX = Vertices[i].Coord.X;
240                 else if (Vertices[i].Coord.X > maxX)
241                     maxX = Vertices[i].Coord.X;
242
243                 if (Vertices[i].Coord.Y < minY)
244                     minY = Vertices[i].Coord.Y;
245                 else if (Vertices[i].Coord.Y > maxY)
246                     maxY = Vertices[i].Coord.Y;
247
248                 if (Vertices[i].Coord.Z < minZ)
249                     minZ = Vertices[i].Coord.Z;
250                 else if (Vertices[i].Coord.Z > maxZ)
251                     maxZ = Vertices[i].Coord.Z;
252             }
253
254             // Calculate the center-point from the bounding box edges
255             RenderData.Center = new Vector3((minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2);
256
257             // Generate the index array
258             RenderData.Indices = new ushort[NumFaces * 3];
259             current = 0;
260             for (int i = 0; i < NumFaces; i++)
261             {
262                 RenderData.Indices[current++] = (ushort)Faces[i].Indices[0];
263                 RenderData.Indices[current++] = (ushort)Faces[i].Indices[1];
264                 RenderData.Indices[current++] = (ushort)Faces[i].Indices[2];
265             }
266
267             // Generate the texcoord array
268             RenderData.TexCoords = new float[NumVertices * 2];
269             current = 0;
270             for (int i = 0; i < NumVertices; i++)
271             {
272                 RenderData.TexCoords[current++] = Vertices[i].TexCoord.X;
273                 RenderData.TexCoords[current++] = Vertices[i].TexCoord.Y;
274             }
275
276             RenderData.weights = new float[NumVertices];
277             for (int i = 0; i < NumVertices; i++)
278             {
279                 RenderData.weights[i] = Vertices[i].Weight;
280             }
281
282             RenderData.skinJoints = new string[SkinJoints.Length + 3];
283             for (int i = 1; i < SkinJoints.Length; i++)
284             {
285                 RenderData.skinJoints[i] = SkinJoints[i];
286             }
287
288
289         }
290
291         public override void LoadLODMesh(int level, string filename)
292         {
293             LODMesh lod = new LODMesh();
294             lod.LoadMesh(filename);
295             LodMeshes[level] = lod;
296         }
297
298         public void applyjointweights()
299         {
300
301             /*Each weight actually contains two pieces of information. 
302              * The number to the left of the decimal point is the index of the joint and also 
303              * implicitly indexes to the following joint. The actual weight is to the right of 
304              * the decimal point and interpolates between these two joints. The index is into an 
305              * "expanded" list of joints, not just a linear array of the joints as defined in the 
306              * skeleton file. In particular, any joint that has more than one child will be repeated 
307              * in the list for each of its children.
308              */
309
310             float weight = -9999;
311             int jointindex = 0;
312             float factor;
313
314             Bone ba = null;
315             Bone bb = null;
316
317             for (int v = 0, x = 0; v < RenderData.Vertices.Length; v = v + 3, x++)
318             {
319                 if (weight != RenderData.weights[x])
320                 {
321
322                     jointindex = (int)Math.Floor(weight = RenderData.weights[x]);
323                     factor = RenderData.weights[x] - jointindex;
324                     weight = weight - jointindex;
325
326                     string jointname = "", jointname2 = "";
327
328                     switch (Name)
329                     {
330                         case "upperBodyMesh":
331                             jointname = skeleton.mUpperMeshMapping[jointindex];
332                             jointindex++;
333                             jointname2 = skeleton.mUpperMeshMapping[jointindex];
334                             break;
335
336                         case "lowerBodyMesh":
337                             jointname = skeleton.mLowerMeshMapping[jointindex];
338                             jointindex++;
339                             jointname2 = skeleton.mLowerMeshMapping[jointindex];
340                             break;
341
342                         case "headMesh":
343                             jointname = skeleton.mHeadMeshMapping[jointindex];
344                             jointindex++;
345                             jointname2 = skeleton.mHeadMeshMapping[jointindex];
346                             break;
347
348                         case "eyeBallRightMesh":
349                             jointname = "mHead";
350                             jointname2 = "mEyeRight";
351                             break;
352
353                         case "eyeBallLeftMesh":
354                             jointname = "mHead";
355                             jointname2 = "mEyeLeft";
356                             break;
357
358                         case "eyelashMesh":
359                         case "hairMesh":
360                             jointname = "mHead";
361                             jointname2 = "mSkull";
362                             break;
363
364                         default:
365                             return;
366
367                     }
368
369                     ba = av.skel.mBones[jointname];
370
371
372                     if (jointname2 == "")
373                     {
374                         bb = null;
375                     }
376                     else
377                     {
378                         bb = av.skel.mBones[jointname2];
379                     }
380                 }
381
382                 //Special cases 0 is not used
383                 // ON upper torso 5 and 10 are not used
384                 // 4 is neck and 6 and 11 are the left and right collar bones
385
386
387                 //TODO use the SRT matrix to do this!
388
389                 Vector3 lerpa;
390                 Vector3 offseta;
391                 Quaternion rota;
392
393                 Vector3 lerpb;
394                 Vector3 offsetb;
395                 Quaternion rotb;
396
397                 Vector3 pos;
398
399                 Vector3 posa = new Vector3(MorphRenderData.Vertices[v], MorphRenderData.Vertices[v + 1], MorphRenderData.Vertices[v + 2]);
400
401
402                 if (bb != null)
403                 {
404                     lerpa = ba.getDeltaOffset();
405                     offseta = ba.getTotalOffset();
406                     rota = ba.getTotalRotation();
407
408                     lerpb = bb.getDeltaOffset();
409                     offsetb = bb.getTotalOffset();
410                     rotb = bb.getTotalRotation();
411
412                     Vector3 posb = new Vector3(MorphRenderData.Vertices[v], MorphRenderData.Vertices[v + 1], MorphRenderData.Vertices[v + 2]);
413
414                     //move back to mesh local coords
415                     posa = posa - offseta;
416
417                     // apply rotated offset
418                     posa = ((posa + lerpa) * ba.scale) * rota;
419                     //move back to avatar local coords
420                     posa = posa + offseta;
421
422                     //move back to mesh local coords
423                     posb = posb - offsetb;
424
425                     // apply rotated offset
426                     posb = ((posb + lerpb) * bb.scale) * rotb;
427                     //move back to avatar local coords
428                     posb = posb + offsetb;
429
430                     //LERP the two points to produce smooth skinning ;-)
431                     pos = Vector3.Lerp(posa, posb, weight);
432
433                 }
434                 else
435                 {
436                     lerpa = ba.getDeltaOffset();
437                     offseta = ba.getTotalOffset();
438                     rota = ba.getTotalRotation();
439
440                     //move back to mesh local coords
441                     posa = posa - offseta;
442
443                     // apply rotated offset
444                     posa = ((posa + lerpa) * ba.scale) * rota;
445                     //move back to avatar local coords
446                     posa = posa + offseta;
447
448                     //Only one bone contributing so its 100% that one.
449                     pos = posa;
450
451                 }
452
453                 RenderData.Vertices[v] = pos.X;
454                 RenderData.Vertices[v + 1] = pos.Y;
455                 RenderData.Vertices[v + 2] = pos.Z;
456             }
457         }
458
459         public void resetallmorphs()
460         {
461             for (int i = 0; i < OrigRenderData.Vertices.Length / 3; i++)
462             {
463
464                 MorphRenderData.Vertices[i * 3] = OrigRenderData.Vertices[i * 3];
465                 MorphRenderData.Vertices[(i * 3) + 1] = OrigRenderData.Vertices[i * 3 + 1];
466                 MorphRenderData.Vertices[(i * 3) + 2] = OrigRenderData.Vertices[i * 3 + 2];
467
468                 MorphRenderData.Normals[i * 3] = OrigRenderData.Normals[i * 3];
469                 MorphRenderData.Normals[(i * 3) + 1] = OrigRenderData.Normals[i * 3 + 1];
470                 MorphRenderData.Normals[(i * 3) + 2] = OrigRenderData.Normals[i * 3 + 2];
471
472                 RenderData.TexCoords[i * 2] = OrigRenderData.TexCoords[i * 2];
473                 RenderData.TexCoords[(i * 2) + 1] = OrigRenderData.TexCoords[i * 2 + 1];
474
475             }
476
477         }
478
479         public void morphmesh(Morph morph, float weight)
480         {
481             // Logger.Log(String.Format("Applying morph {0} weight {1}",morph.Name,weight),Helpers.LogLevel.Debug);
482
483             for (int v = 0; v < morph.NumVertices; v++)
484             {
485                 MorphVertex mvx = morph.Vertices[v];
486
487                 uint i = mvx.VertexIndex;
488
489                 MorphRenderData.Vertices[i * 3] = MorphRenderData.Vertices[i * 3] + mvx.Coord.X * weight;
490                 MorphRenderData.Vertices[(i * 3) + 1] = MorphRenderData.Vertices[i * 3 + 1] + mvx.Coord.Y * weight;
491                 MorphRenderData.Vertices[(i * 3) + 2] = MorphRenderData.Vertices[i * 3 + 2] + mvx.Coord.Z * weight;
492
493                 MorphRenderData.Normals[i * 3] = MorphRenderData.Normals[i * 3] + mvx.Normal.X * weight;
494                 MorphRenderData.Normals[(i * 3) + 1] = MorphRenderData.Normals[(i * 3) + 1] + mvx.Normal.Y * weight;
495                 MorphRenderData.Normals[(i * 3) + 2] = MorphRenderData.Normals[(i * 3) + 2] + mvx.Normal.Z * weight;
496
497                 RenderData.TexCoords[i * 2] = OrigRenderData.TexCoords[i * 2] + mvx.TexCoord.X * weight;
498                 RenderData.TexCoords[(i * 2) + 1] = OrigRenderData.TexCoords[i * 2 + 1] + mvx.TexCoord.Y * weight;
499
500             }
501         }
502     }
503
504     public class GLAvatar
505     {
506         private static Dictionary<string, GLMesh> _defaultmeshes = new Dictionary<string, GLMesh>();
507         public Dictionary<string, GLMesh> _meshes = new Dictionary<string, GLMesh>();
508
509         public skeleton skel = new skeleton();
510         public static Dictionary<int, attachment_point> attachment_points = new Dictionary<int, attachment_point>();
511
512         public bool _wireframe = true;
513         public bool _showSkirt = false;
514
515         public VisualParamEx.EparamSex msex;
516
517         public byte[] VisualAppearanceParameters = new byte[1024];
518         bool vpsent = false;
519         static bool lindenMeshesLoaded = false;
520
521         public GLAvatar()
522         {
523             lock (_defaultmeshes) foreach (KeyValuePair<string, GLMesh> kvp in _defaultmeshes)
524                 {
525                     GLMesh mesh = new GLMesh(kvp.Value, this); // Instance our meshes
526                     _meshes.Add(kvp.Key, mesh);
527
528                 }
529         }
530
531         public static void dumptweaks()
532         {
533
534             for (int x = 0; x < VisualParamEx.tweakable_params.Count; x++)
535             {
536                 VisualParamEx vpe = (VisualParamEx)VisualParamEx.tweakable_params.GetByIndex(x);
537                 Console.WriteLine(string.Format("{0} is {1}", x, vpe.Name));
538             }
539
540         }
541
542         public static void loadlindenmeshes2(string LODfilename)
543         {
544             // Already have mashes loaded?
545             if (lindenMeshesLoaded) return;
546
547             attachment_points.Clear();
548
549
550             string basedir = Directory.GetCurrentDirectory() + System.IO.Path.DirectorySeparatorChar + "character" + System.IO.Path.DirectorySeparatorChar;
551
552             XmlDocument lad = new XmlDocument();
553             lad.Load(basedir + LODfilename);
554
555             //Firstly read the skeleton section this contains attachment point info and the bone deform info for visual params
556             // And load the skeleton file in to the bones class
557
558             XmlNodeList skeleton = lad.GetElementsByTagName("skeleton");
559             string skeletonfilename = skeleton[0].Attributes.GetNamedItem("file_name").Value;
560             Bone.loadbones(skeletonfilename);
561
562             // Next read all the skeleton child nodes, we have attachment points and bone deform params
563             // attachment points are an offset and rotation from a bone location
564             // the name of the bone they reference is the joint paramater
565             // params in the skeleton nodes are bone deforms, eg leg length changes the scale of the leg bones
566
567             foreach (XmlNode skeletonnode in skeleton[0].ChildNodes)
568             {
569                 if (skeletonnode.Name == "attachment_point")
570                 {
571                     attachment_point point = new attachment_point(skeletonnode);
572                     attachment_points.Add(point.id, point);
573                 }
574             }
575
576             // Parse all visual paramaters in one go
577             // we can dedue type on the fly
578             XmlNodeList paramss = lad.GetElementsByTagName("param");
579             foreach (XmlNode paramNode in paramss)
580             {
581                 VisualParamEx vp = new VisualParamEx(paramNode);
582             }
583
584             //Now we parse the mesh nodes, mesh nodes reference a particular LLM file with a LOD
585
586             XmlNodeList meshes = lad.GetElementsByTagName("mesh");
587             foreach (XmlNode meshNode in meshes)
588             {
589                 string type = meshNode.Attributes.GetNamedItem("type").Value;
590                 int lod = Int32.Parse(meshNode.Attributes.GetNamedItem("lod").Value);
591                 string fileName = meshNode.Attributes.GetNamedItem("file_name").Value;
592
593                 GLMesh mesh = null;
594                 lock (_defaultmeshes)
595                     mesh = (_defaultmeshes.ContainsKey(type) ? _defaultmeshes[type] : new GLMesh(type));
596
597                 // Set up the texture elemenets for each mesh
598                 // And hack the eyeball position
599                 switch (mesh.Name)
600                 {
601                     case "lowerBodyMesh":
602                         mesh.teFaceID = (int)AvatarTextureIndex.LowerBaked;
603                         break;
604
605                     case "upperBodyMesh":
606                         mesh.teFaceID = (int)AvatarTextureIndex.UpperBaked;
607                         break;
608
609                     case "headMesh":
610                         mesh.teFaceID = (int)AvatarTextureIndex.HeadBaked;
611                         break;
612
613                     case "hairMesh":
614                         mesh.teFaceID = (int)AvatarTextureIndex.HairBaked;
615                         break;
616
617                     case "eyelashMesh":
618                         mesh.teFaceID = (int)AvatarTextureIndex.HeadBaked;
619                         break;
620
621                     case "eyeBallRightMesh":
622                         mesh.teFaceID = (int)AvatarTextureIndex.EyesBaked;
623                         break;
624
625                     case "eyeBallLeftMesh":
626                         mesh.teFaceID = (int)AvatarTextureIndex.EyesBaked;
627                         break;
628
629                     case "skirtMesh":
630                         mesh.teFaceID = (int)AvatarTextureIndex.SkirtBaked;
631                         break;
632
633                     default:
634                         mesh.teFaceID = 0;
635                         break;
636                 }
637
638                 if (lod == 0)
639                     mesh.LoadMesh(basedir + fileName);
640                 else
641                     mesh.LoadLODMesh(lod, basedir + fileName);
642
643                 if (lod == 0)
644                 {
645                     switch (mesh.Name)
646                     {
647                         case "eyeBallLeftMesh":
648                             lock (Bone.mBones) mesh.setMeshPos(Bone.mBones["mEyeLeft"].getTotalOffset());
649                             break;
650
651                         case "eyeBallRightMesh":
652                             lock (Bone.mBones) mesh.setMeshPos(Bone.mBones["mEyeRight"].getTotalOffset());
653                             break;
654
655                         case "eyelashMesh":
656                             lock (Bone.mBones) mesh.setMeshPos(Bone.mBones["mHead"].getTotalOffset());
657                             break;
658
659                         case "hairMesh":
660                             //mesh.setMeshPos(Bone.mBones["mHead"].getTotalOffset());
661                             break;
662
663                         default:
664                             break;
665                     }
666                 }
667
668                 lock (_defaultmeshes) _defaultmeshes[type] = mesh;
669
670             }
671
672             lindenMeshesLoaded = true;
673         }
674
675         public void applyMorph(Avatar av, int param, float weight)
676         {
677             VisualParamEx vpx;
678
679             if (VisualParamEx.allParams.TryGetValue(param, out vpx))
680             {
681                 applyMorph(vpx, av, weight);
682
683                 // a morph ID may apply to more than one mesh (duplicate VP IDs)
684                 // in this case also apply to all other identical IDs
685                 foreach (VisualParamEx cvpx in vpx.identicalIds)
686                 {
687                     applyMorph(cvpx, av, weight);
688                 }
689             }
690         }
691
692         public void applyMorph(VisualParamEx vpx, Avatar av, float weight)
693         {
694
695             weight = Utils.Clamp(weight, 0.0f, 1.0f);
696             float value = Utils.Lerp(vpx.MinValue, vpx.MaxValue, weight);
697
698             // don't do anything for less than 1% change
699             if (value > -0.001 && value < 0.001)
700                 return;
701
702             // Morphs are mesh deforms
703             if (vpx.pType == VisualParamEx.ParamType.TYPE_MORPH)
704             {
705                 // Its a morph
706                 GLMesh mesh;
707                 if (_meshes.TryGetValue(vpx.morphmesh, out mesh))
708                 {
709                     foreach (LindenMesh.Morph morph in mesh.Morphs) //optimise me to a dictionary
710                     {
711                         if (morph.Name == vpx.Name)
712                         {
713                             if (mesh.Name == "skirtMesh" && _showSkirt == false)
714                                 return;
715
716                             // Logger.Log(String.Format("Applying morph {0} ID {2} weight {1} mesh {3}",morph.Name,weight,vpx.ParamID,mesh.Name),Helpers.LogLevel.Debug);
717
718                             mesh.morphmesh(morph, value);
719
720                         }
721                     }
722                 }
723             }
724
725
726             // Driver type
727             // A driver drives multiple slave visual paramaters
728             if (vpx.pType == VisualParamEx.ParamType.TYPE_DRIVER)
729             {
730
731                 foreach (VisualParamEx.driven child in vpx.childparams)
732                 {
733
734                     /***** BEGIN UNGRACEFULL CODE STEALING ******/
735
736                     //  driven    ________
737                     //  ^        /|       |\       ^
738                     //  |       / |       | \      |
739                     //  |      /  |       |  \     |
740                     //  |     /   |       |   \    |
741                     //  |    /    |       |    \   |
742                     //-------|----|-------|----|-------> driver
743                     //  | min1   max1    max2  min2
744
745
746                     if (child.hasMinMax == false)
747                     {
748                         applyMorph(av, child.id, weight);
749                         continue;
750                     }
751
752                     float driven_weight = vpx.DefaultValue;
753                     float driven_max = VisualParamEx.allParams[child.id].MaxValue;
754                     float driven_min = VisualParamEx.allParams[child.id].MinValue;
755                     float input_weight = weight;
756
757                     float min_weight = vpx.MinValue;
758                     float max_weight = vpx.MaxValue;
759
760                     if (input_weight <= child.min1)
761                     {
762                         if (child.min1 == child.max1 &&
763                             child.min1 <= min_weight)
764                         {
765                             driven_weight = driven_max;
766                         }
767                         else
768                         {
769                             driven_weight = driven_min;
770                         }
771                     }
772                     else
773                         if (input_weight <= child.max1)
774                         {
775                             float t = (input_weight - child.min1) / (child.max1 - child.min1);
776                             driven_weight = driven_min + t * (driven_max - driven_min);
777                         }
778                         else
779                             if (input_weight <= child.max2)
780                             {
781                                 driven_weight = driven_max;
782                             }
783                             else
784                                 if (input_weight <= child.min2)
785                                 {
786                                     float t = (input_weight - child.max2) / (child.min2 - child.max2);
787                                     driven_weight = driven_max + t * (driven_min - driven_max);
788                                 }
789                                 else
790                                 {
791                                     if (child.max2 >= max_weight)
792                                     {
793                                         driven_weight = driven_max;
794                                     }
795                                     else
796                                     {
797                                         driven_weight = driven_min;
798                                     }
799                                 }
800
801
802                     /***** END UNGRACEFULL CODE STEALING ******/
803
804                     applyMorph(av, child.id, driven_weight);
805
806                 }
807
808                 return;
809             }
810
811             //Is this a bone deform?
812             if (vpx.pType == VisualParamEx.ParamType.TYPE_BONEDEFORM)
813             {
814                 //  scale="0 0 .3" />
815                 //   value_min="-1"
816                 // value_max="1"
817
818                 foreach (KeyValuePair<string, BoneDeform> kvp in vpx.BoneDeforms)
819                 {
820                     skel.scalebone(kvp.Key, Vector3.One + (kvp.Value.scale * value));
821                     skel.offsetbone(kvp.Key, kvp.Value.offset * value);
822                 }
823             }
824         }
825
826         public void morph(Avatar av)
827         {
828
829             if (av.VisualParameters == null)
830                 return;
831
832             WorkPool.QueueUserWorkItem(sync =>
833             {
834                 int x = 0;
835
836                 // We need a lock here as we may get multiple packets thrown at us and we should at least
837                 // process them in turn not 1/2 process one then start to process the next. 
838                 // That said av might not be the best lock object, but it will do for the moment
839                 lock (av)
840                 {
841                     if (av.VisualParameters.Length > 123)
842                     {
843                         if (av.VisualParameters[31] > 127)
844                         {
845                             msex = VisualParamEx.EparamSex.SEX_MALE;
846                         }
847                         else
848                         {
849                             msex = VisualParamEx.EparamSex.SEX_FEMALE;
850                         }
851                     }
852
853                     foreach (GLMesh mesh in _meshes.Values)
854                     {
855                         mesh.resetallmorphs();
856                     }
857
858                     skel.resetbonescales();
859
860                     foreach (byte vpvalue in av.VisualParameters)
861                     {
862                         if (x >= VisualParamEx.tweakable_params.Count)
863                         {
864                             //Logger.Log("Two many visual paramaters in Avatar appearance", Helpers.LogLevel.Warning);
865                             break;
866                         }
867
868                         VisualParamEx vpe = (VisualParamEx)VisualParamEx.tweakable_params.GetByIndex(x);
869
870                         if (vpe.sex != VisualParamEx.EparamSex.SEX_BOTH && vpe.sex != msex)
871                         {
872                             x++;
873                             continue;
874                         }
875
876                         VisualAppearanceParameters[x] = vpvalue;
877
878                         float value = (vpvalue / 255.0f);
879                         this.applyMorph(av, vpe.ParamID, value);
880
881                         x++;
882                     }
883
884                     vpsent = true;
885                     this.skel.mNeedsMeshRebuild = true;
886                     // Don't update actual meshes here anymore, we do it every frame because of animation anyway
887
888                 }
889             });
890         }
891     }
892
893     public class joint
894     {
895         public Vector3 offset;
896         public Quaternion rotation;
897     }
898
899     public class animationwrapper
900     {
901         public BinBVHAnimationReader anim;
902         public float mRunTime;
903         public UUID mAnimation;
904         public bool mPotentialyDead = false;
905
906         public enum animstate
907         {
908             STATE_WAITINGASSET,
909             STATE_EASEIN,
910             STATE_EASEOUT,
911             STATE_PLAY,
912             STATE_STOP
913         }
914
915         public animstate playstate;
916
917         public animationwrapper(BinBVHAnimationReader anim)
918         {
919             this.anim = anim;
920             playstate = animstate.STATE_EASEIN;
921             mRunTime = 0;
922         }
923
924         public animationwrapper(UUID key)
925         {
926             mAnimation = key;
927             playstate = animstate.STATE_WAITINGASSET;
928             mRunTime = 0;
929         }
930
931         public void stopanim()
932         {
933             //Logger.Log(string.Format("Animation {0} marked as stopped",mAnimation),Helpers.LogLevel.Info);
934             playstate = animstate.STATE_STOP;
935         }
936     }
937
938     public class skeleton
939     {
940         public Dictionary<string, Bone> mBones;
941         private Dictionary<string, int> mPriority = new Dictionary<string, int>();
942         private Dictionary<string, joint> jointdeforms = new Dictionary<string, joint>();
943
944         public static Dictionary<int, string> mUpperMeshMapping = new Dictionary<int, string>();
945         public static Dictionary<int, string> mLowerMeshMapping = new Dictionary<int, string>();
946         public static Dictionary<int, string> mHeadMeshMapping = new Dictionary<int, string>();
947
948         // public List<BinBVHAnimationReader> mAnimations = new List<BinBVHAnimationReader>();
949         public Dictionary<UUID, animationwrapper> mAnimationsWrapper = new Dictionary<UUID, animationwrapper>();
950
951         public static Dictionary<UUID, RenderAvatar> mAnimationTransactions = new Dictionary<UUID, RenderAvatar>();
952
953         public static Dictionary<UUID, BinBVHAnimationReader> mAnimationCache = new Dictionary<UUID, BinBVHAnimationReader>();
954
955         public bool mNeedsUpdate = false;
956         public bool mNeedsMeshRebuild = true;
957
958
959         public struct binBVHJointState
960         {
961             public float currenttime_rot;
962             public int lastkeyframe_rot;
963             public int nextkeyframe_rot;
964
965             public float currenttime_pos;
966             public int lastkeyframe_pos;
967             public int nextkeyframe_pos;
968
969             public int pos_loopinframe;
970             public int pos_loopoutframe;
971
972             public int rot_loopinframe;
973             public int rot_loopoutframe;
974
975             public Quaternion easeoutrot;
976             public float easeoutfactor;
977
978         }
979
980
981         public skeleton()
982         {
983
984             mBones = new Dictionary<string, Bone>();
985
986             lock (Bone.mBones) foreach (Bone src in Bone.mBones.Values)
987                 {
988                     Bone newbone = new Bone(src);
989                     mBones.Add(newbone.name, newbone);
990                 }
991
992             //rebuild the skeleton structure on the new copy
993             foreach (Bone src in mBones.Values)
994             {
995                 if (src.mParentBone != null)
996                 {
997                     src.parent = mBones[src.mParentBone];
998                     src.parent.children.Add(src);
999                 }
1000             }
1001
1002             //FUDGE
1003             if (mUpperMeshMapping.Count == 0)
1004             {
1005                 mUpperMeshMapping.Add(1, "mPelvis");
1006                 mUpperMeshMapping.Add(2, "mTorso");
1007                 mUpperMeshMapping.Add(3, "mChest");
1008                 mUpperMeshMapping.Add(4, "mNeck");
1009                 mUpperMeshMapping.Add(5, "mNeck");
1010                 mUpperMeshMapping.Add(6, "mCollarLeft");
1011                 mUpperMeshMapping.Add(7, "mShoulderLeft");
1012                 mUpperMeshMapping.Add(8, "mElbowLeft");
1013                 mUpperMeshMapping.Add(9, "mWristLeft");
1014                 mUpperMeshMapping.Add(10, "mNeck");  // this case might fail for mWriteLeft and mNeck acting together?
1015                 mUpperMeshMapping.Add(11, "mCollarRight");
1016                 mUpperMeshMapping.Add(12, "mShoulderRight");
1017                 mUpperMeshMapping.Add(13, "mElbowRight");
1018                 mUpperMeshMapping.Add(14, "mWristRight");
1019                 mUpperMeshMapping.Add(15, "");
1020
1021                 mLowerMeshMapping.Add(1, "mPelvis");
1022                 mLowerMeshMapping.Add(2, "mHipRight");
1023                 mLowerMeshMapping.Add(3, "mKneeRight");
1024                 mLowerMeshMapping.Add(4, "mAnkleRight");
1025                 mLowerMeshMapping.Add(5, "mPelvis");
1026                 mLowerMeshMapping.Add(6, "mHipLeft");
1027                 mLowerMeshMapping.Add(7, "mKneeLeft");
1028                 mLowerMeshMapping.Add(8, "mAnkleLeft");
1029                 mLowerMeshMapping.Add(9, "");
1030
1031                 mHeadMeshMapping.Add(1, "mNeck");
1032                 mHeadMeshMapping.Add(2, "mHead");
1033                 mHeadMeshMapping.Add(3, "");
1034
1035             }
1036
1037         }
1038
1039         public void processAnimation(UUID mAnimID)
1040         {
1041             if (mAnimationsWrapper.ContainsKey(mAnimID))
1042             {
1043                 // Its an existing animation, we may need to do a seq update but we don't yet
1044                 // support that
1045                 mAnimationsWrapper[mAnimID].playstate = animationwrapper.animstate.STATE_WAITINGASSET;
1046                 mAnimationsWrapper[mAnimID].mPotentialyDead = false;
1047             }
1048             else
1049             {
1050                 // Its a new animation do the decode dance
1051                 animationwrapper aw = new animationwrapper(mAnimID);
1052                 mAnimationsWrapper.Add(mAnimID, aw);
1053
1054             }
1055         }
1056
1057         public void resetbonescales()
1058         {
1059             foreach (KeyValuePair<string, Bone> src in mBones)
1060             {
1061                 src.Value.scale = Vector3.One;
1062                 src.Value.offset_pos = Vector3.Zero;
1063             }
1064         }
1065
1066         public void deformbone(string name, Vector3 pos, Quaternion rotation)
1067         {
1068             Bone bone;
1069             if (mBones.TryGetValue(name, out bone))
1070             {
1071                 bone.deformbone(pos, rotation);
1072             }
1073         }
1074
1075         public void scalebone(string name, Vector3 scale)
1076         {
1077
1078             Bone bone;
1079             if (mBones.TryGetValue(name, out bone))
1080             {
1081                 // Logger.Log(String.Format("scalebone() {0} {1}", name, scale.ToString()),Helpers.LogLevel.Info);
1082                 bone.scalebone(scale);
1083             }
1084         }
1085
1086         public void offsetbone(string name, Vector3 offset)
1087         {
1088             Bone bone;
1089             if (mBones.TryGetValue(name, out bone))
1090             {
1091                 bone.offsetbone(offset);
1092             }
1093         }
1094
1095         //TODO check offset and rot calcuations should each offset be multiplied by its parent rotation in
1096         // a standard child/parent rot/offset way?
1097         public Vector3 getOffset(string bonename)
1098         {
1099             Bone b;
1100             if (mBones.TryGetValue(bonename, out b))
1101             {
1102                 return (b.getTotalOffset());
1103             }
1104             else
1105             {
1106                 return Vector3.Zero;
1107             }
1108         }
1109
1110         public Quaternion getRotation(string bonename)
1111         {
1112             Bone b;
1113             if (mBones.TryGetValue(bonename, out b))
1114             {
1115                 return (b.getTotalRotation());
1116             }
1117             else
1118             {
1119                 return Quaternion.Identity;
1120             }
1121         }
1122
1123
1124         public void flushanimations()
1125         {
1126             lock (mAnimationsWrapper)
1127             {
1128                 List<UUID> kills = new List<UUID>();
1129                 foreach (animationwrapper ar in mAnimationsWrapper.Values)
1130                 {
1131                     if (ar.playstate == animationwrapper.animstate.STATE_STOP)
1132                     {
1133                         kills.Add(ar.mAnimation);
1134                     }
1135
1136                     ar.mPotentialyDead = true;
1137                 }
1138
1139                 foreach (UUID key in kills)
1140                 {
1141                     mAnimationsWrapper.Remove(key);
1142                     //Logger.Log(string.Format("Removing dead animation {0} from av", key), Helpers.LogLevel.Info);
1143                 }
1144             }
1145         }
1146
1147         public void flushanimationsfinal()
1148         {
1149             lock (mAnimationsWrapper)
1150             {
1151                 foreach (animationwrapper ar in mAnimationsWrapper.Values)
1152                 {
1153                     if (ar.mPotentialyDead == true)
1154                     {
1155                         // Logger.Log(string.Format("Animation {0} is being marked for easeout (dead)",ar.mAnimation.ToString()),Helpers.LogLevel.Info);
1156                         // Should we just stop dead? i think not it may get jerky
1157                         ar.playstate = animationwrapper.animstate.STATE_EASEOUT;
1158                         ar.mRunTime = 0; //fix me nasty hack
1159                     }
1160                 }
1161             }
1162
1163         }
1164
1165         // Add animations to the global decoded list
1166         // TODO garbage collect unused animations somehow
1167         public static void addanimation(OpenMetaverse.Assets.Asset asset, UUID tid, BinBVHAnimationReader b, UUID animKey)
1168         {
1169             RenderAvatar av;
1170             mAnimationTransactions.TryGetValue(tid, out av);
1171             if (av == null)
1172                 return;
1173
1174             mAnimationTransactions.Remove(tid);
1175
1176             if (asset != null)
1177             {
1178                 b = new BinBVHAnimationReader(asset.AssetData);
1179                 mAnimationCache[asset.AssetID] = b;
1180                 Logger.Log("Adding new decoded animaton known animations " + asset.AssetID.ToString(), Helpers.LogLevel.Info);
1181             }
1182
1183             if (!av.glavatar.skel.mAnimationsWrapper.ContainsKey(animKey))
1184             {
1185                 Logger.Log(String.Format("Animation {0} is not in mAnimationsWrapper! ", animKey), Helpers.LogLevel.Warning);
1186                 return;
1187             }
1188
1189             // This sets the anim in the wrapper class;
1190             av.glavatar.skel.mAnimationsWrapper[animKey].anim = b;
1191
1192             int pos = 0;
1193             foreach (binBVHJoint joint in b.joints)
1194             {
1195                 binBVHJointState state;
1196
1197                 state.lastkeyframe_rot = 0;
1198                 state.nextkeyframe_rot = 1;
1199
1200                 state.lastkeyframe_pos = 0;
1201                 state.nextkeyframe_pos = 1;
1202
1203                 state.currenttime_rot = 0;
1204                 state.currenttime_pos = 0;
1205
1206                 state.pos_loopinframe = 0;
1207                 state.pos_loopoutframe = joint.positionkeys.Length - 1;
1208
1209                 state.rot_loopinframe = 0;
1210                 state.rot_loopoutframe = joint.rotationkeys.Length - 1;
1211
1212                 state.easeoutfactor = 1.0f;
1213                 state.easeoutrot = Quaternion.Identity;
1214
1215                 if (b.Loop == true)
1216                 {
1217                     int frame = 0;
1218                     foreach (binBVHJointKey key in joint.rotationkeys)
1219                     {
1220                         if (key.time == b.InPoint)
1221                         {
1222                             state.rot_loopinframe = frame;
1223                         }
1224
1225                         if (key.time == b.OutPoint)
1226                         {
1227                             state.rot_loopoutframe = frame;
1228                         }
1229
1230                         frame++;
1231                     }
1232
1233                     frame = 0;
1234                     foreach (binBVHJointKey key in joint.positionkeys)
1235                     {
1236                         if (key.time == b.InPoint)
1237                         {
1238                             state.pos_loopinframe = frame;
1239                         }
1240
1241                         if (key.time == b.OutPoint)
1242                         {
1243                             state.pos_loopoutframe = frame;
1244                         }
1245
1246                         frame++;
1247                     }
1248
1249                 }
1250
1251                 b.joints[pos].Tag = state;
1252                 pos++;
1253             }
1254
1255             av.glavatar.skel.mAnimationsWrapper[animKey].playstate = animationwrapper.animstate.STATE_EASEIN;
1256             recalcpriorities(av);
1257
1258         }
1259
1260         public static void recalcpriorities(RenderAvatar av)
1261         {
1262
1263             lock (av.glavatar.skel.mAnimationsWrapper)
1264             {
1265                 //av.glavatar.skel.mAnimationsWrapper.Add(new animationwrapper(b));
1266
1267                 //pre calculate all joint priorities here
1268                 av.glavatar.skel.mPriority.Clear();
1269
1270                 foreach (KeyValuePair<UUID, animationwrapper> kvp in av.glavatar.skel.mAnimationsWrapper)
1271                 {
1272                     int jpos = 0;
1273                     animationwrapper ar = kvp.Value;
1274                     if (ar.anim == null)
1275                         continue;
1276
1277                     foreach (binBVHJoint joint in ar.anim.joints)
1278                     {
1279                         if (ar.anim == null)
1280                             continue;
1281
1282                         //warning struct copy non reference
1283                         binBVHJointState state = (binBVHJointState)ar.anim.joints[jpos].Tag;
1284
1285                         if (ar.playstate == animationwrapper.animstate.STATE_STOP || ar.playstate == animationwrapper.animstate.STATE_EASEOUT)
1286                             continue;
1287
1288                         //FIX ME need to consider ease out here on priorities somehow
1289
1290
1291                         int prio = 0;
1292                         //Quick hack to stack animations in the correct order
1293                         //TODO we need to do this per joint as they all have their own priorities as well ;-(
1294                         if (av.glavatar.skel.mPriority.TryGetValue(joint.Name, out prio))
1295                         {
1296                             if (prio > (ar.anim.Priority))
1297                                 continue;
1298                         }
1299
1300                         av.glavatar.skel.mPriority[joint.Name] = ar.anim.Priority;
1301
1302                         jpos++;
1303
1304                         //av.glavatar.skel.mAnimationsWrapper[kvp.Key].playstate = animationwrapper.animstate.STATE_EASEIN;
1305
1306                     }
1307                 }
1308             }
1309
1310         }
1311
1312         public void animate(float lastframetime)
1313         {
1314
1315             lock (mAnimationsWrapper)
1316             {
1317
1318                 jointdeforms.Clear();
1319
1320                 foreach (animationwrapper ar in mAnimationsWrapper.Values)
1321                 {
1322
1323                     if (ar.playstate == animationwrapper.animstate.STATE_WAITINGASSET)
1324                         continue;
1325
1326                     if (ar.anim == null)
1327                         continue;
1328
1329                     ar.mRunTime += lastframetime;
1330
1331                     // EASE FACTORS
1332                     // Caclulate ease factors now they are common to all joints in a given animation
1333                     float factor = 1.0f;
1334
1335                     if (ar.playstate == animationwrapper.animstate.STATE_EASEIN)
1336                     {
1337                         if (ar.mRunTime >= ar.anim.EaseInTime)
1338                         {
1339                             ar.playstate = animationwrapper.animstate.STATE_PLAY;
1340                             //Console.WriteLine(String.Format("{0} Now in STATE_PLAY", ar.mAnimation));
1341                         }
1342                         else
1343                         {
1344                             factor = 1.0f - ((ar.anim.EaseInTime - ar.mRunTime) / ar.anim.EaseInTime);
1345                         }
1346
1347                         //Console.WriteLine(String.Format("EASE IN {0} {1}",factor.ToString(),ar.mAnimation));
1348                     }
1349
1350                     if (ar.playstate == animationwrapper.animstate.STATE_EASEOUT)
1351                     {
1352
1353                         if (ar.mRunTime >= ar.anim.EaseOutTime)
1354                         {
1355                             ar.stopanim();
1356                             factor = 0;
1357                             //Console.WriteLine(String.Format("{0} Now in STATE_STOP", ar.mAnimation));
1358
1359                         }
1360                         else
1361                         {
1362                             factor = 1.0f - (ar.mRunTime / ar.anim.EaseOutTime);
1363
1364                         }
1365
1366                         //Console.WriteLine(String.Format("EASE OUT {0} {1}", factor.ToString(), ar.mAnimation));
1367                     }
1368
1369                     // we should not need this, this implies bad math above
1370
1371
1372                     factor = Utils.Clamp(factor, 0.0f, 1.0f);
1373                     //factor = 1.0f;
1374
1375                     //END EASE FACTORS
1376
1377
1378                     int jpos = 0;
1379                     foreach (binBVHJoint joint in ar.anim.joints)
1380                     {
1381                         bool easeoutset = false;
1382                         //warning struct copy non reference
1383                         binBVHJointState state = (binBVHJointState)ar.anim.joints[jpos].Tag;
1384
1385                         if (ar.playstate == animationwrapper.animstate.STATE_STOP)
1386                             continue;
1387
1388                         int prio = 0;
1389                         //Quick hack to stack animations in the correct order
1390                         //TODO we need to do this per joint as they all have their own priorities as well ;-(
1391                         if (mPriority.TryGetValue(joint.Name, out prio))
1392                         {
1393                             //if (prio > (ar.anim.Priority))
1394                             //continue;
1395                         }
1396
1397                         Vector3 poslerp = Vector3.Zero;
1398                         Quaternion rotlerp = Quaternion.Identity;
1399
1400                         // Position
1401                         if (ar.anim.joints[jpos].positionkeys.Length >= 2 && joint.Name == "mPelvis")
1402                         {
1403
1404                             //Console.WriteLine("Animate time " + state.currenttime_pos.ToString());
1405
1406                             state.currenttime_pos += lastframetime;
1407
1408                             float currentime = state.currenttime_pos;
1409                             bool overrun = false;
1410
1411                             if (state.currenttime_pos > ar.anim.OutPoint)
1412                             {
1413                                 //overrun state
1414                                 int itterations = (int)(state.currenttime_pos / ar.anim.OutPoint) + 1;
1415                                 state.currenttime_pos = currentime = ar.anim.InPoint + ((ar.anim.OutPoint - ar.anim.InPoint) - (((ar.anim.OutPoint - ar.anim.InPoint) * itterations) - state.currenttime_pos));
1416                                 overrun = true;
1417                             }
1418
1419                             binBVHJointKey pos_next = ar.anim.joints[jpos].positionkeys[state.nextkeyframe_pos];
1420                             binBVHJointKey pos_last = ar.anim.joints[jpos].positionkeys[state.lastkeyframe_pos];
1421
1422                             // if the current time > than next key frame time we move keyframes
1423                             if (currentime >= pos_next.time || overrun)
1424                             {
1425
1426                                 //Console.WriteLine("bump");
1427                                 state.lastkeyframe_pos++;
1428                                 state.nextkeyframe_pos++;
1429
1430                                 if (ar.anim.Loop)
1431                                 {
1432                                     if (state.nextkeyframe_pos > state.pos_loopoutframe)
1433                                         state.nextkeyframe_pos = state.pos_loopinframe;
1434
1435                                     if (state.lastkeyframe_pos > state.pos_loopoutframe)
1436                                         state.lastkeyframe_pos = state.pos_loopinframe;
1437
1438
1439                                     if (state.nextkeyframe_pos >= ar.anim.joints[jpos].positionkeys.Length)
1440                                         state.nextkeyframe_pos = state.pos_loopinframe;
1441
1442                                     if (state.lastkeyframe_pos >= ar.anim.joints[jpos].positionkeys.Length)
1443                                         state.lastkeyframe_pos = state.pos_loopinframe;
1444
1445                                 }
1446                                 else
1447                                 {
1448                                     if (state.nextkeyframe_pos >= ar.anim.joints[jpos].positionkeys.Length)
1449                                         state.nextkeyframe_pos = ar.anim.joints[jpos].positionkeys.Length - 1;
1450
1451                                     if (state.lastkeyframe_pos >= ar.anim.joints[jpos].positionkeys.Length)
1452                                     {
1453                                         state.lastkeyframe_pos = ar.anim.joints[jpos].positionkeys.Length - 1;
1454
1455                                         ar.playstate = animationwrapper.animstate.STATE_EASEOUT;
1456                                         //animation over
1457                                     }
1458                                 }
1459                             }
1460
1461                             //if (pos_next.time == pos_last.time)
1462                             //{
1463                             //    ar.playstate = animationwrapper.animstate.STATE_EASEOUT;
1464                             //}
1465
1466                             // update the pointers incase they have been moved
1467                             pos_next = ar.anim.joints[jpos].positionkeys[state.nextkeyframe_pos];
1468                             pos_last = ar.anim.joints[jpos].positionkeys[state.lastkeyframe_pos];
1469
1470                             // TODO the lerp/delta is faulty
1471                             // it is not going to handle loop points when we wrap around as last will be > next
1472                             // it also fails when currenttime < last_time which occurs as keyframe[0] is not exactly at
1473                             // t(0).
1474                             float delta = (state.currenttime_pos - pos_last.time) / (pos_next.time - pos_last.time);
1475
1476                             delta = Utils.Clamp(delta, 0f, 1f);
1477                             poslerp = Vector3.Lerp(pos_last.key_element, pos_next.key_element, delta) * factor;
1478
1479                             //Console.WriteLine(string.Format("Time {0} {1} {2} {3} {4}", state.currenttime_pos, delta, poslerp.ToString(), state.lastkeyframe_pos, state.nextkeyframe_pos));
1480
1481                         }
1482
1483                         // end of position
1484
1485                         //rotation
1486
1487                         if (ar.anim.joints[jpos].rotationkeys.Length >= 2)
1488                         {
1489
1490                             state.currenttime_rot += lastframetime;
1491
1492                             float currentime = state.currenttime_rot;
1493                             bool overrun = false;
1494
1495                             if (state.currenttime_rot > ar.anim.OutPoint)
1496                             {
1497                                 //overrun state
1498                                 int itterations = (int)(state.currenttime_rot / ar.anim.OutPoint) + 1;
1499                                 state.currenttime_rot = currentime = ar.anim.InPoint + ((ar.anim.OutPoint - ar.anim.InPoint) - (((ar.anim.OutPoint - ar.anim.InPoint) * itterations) - state.currenttime_rot));
1500                                 overrun = true;
1501                             }
1502
1503                             binBVHJointKey rot_next = ar.anim.joints[jpos].rotationkeys[state.nextkeyframe_rot];
1504                             binBVHJointKey rot_last = ar.anim.joints[jpos].rotationkeys[state.lastkeyframe_rot];
1505
1506                             // if the current time > than next key frame time we move keyframes
1507                             if (currentime >= rot_next.time || overrun)
1508                             {
1509
1510                                 state.lastkeyframe_rot++;
1511                                 state.nextkeyframe_rot++;
1512
1513                                 if (ar.anim.Loop)
1514                                 {
1515                                     if (state.nextkeyframe_rot > state.rot_loopoutframe)
1516                                         state.nextkeyframe_rot = state.rot_loopinframe;
1517
1518                                     if (state.lastkeyframe_rot > state.rot_loopoutframe)
1519                                         state.lastkeyframe_rot = state.rot_loopinframe;
1520
1521                                 }
1522                                 else
1523                                 {
1524                                     if (state.nextkeyframe_rot >= ar.anim.joints[jpos].rotationkeys.Length)
1525                                         state.nextkeyframe_rot = ar.anim.joints[jpos].rotationkeys.Length - 1;
1526
1527                                     if (state.lastkeyframe_rot >= ar.anim.joints[jpos].rotationkeys.Length)
1528                                     {
1529                                         state.lastkeyframe_rot = ar.anim.joints[jpos].rotationkeys.Length - 1;
1530
1531                                         ar.playstate = animationwrapper.animstate.STATE_EASEOUT;
1532                                         //animation over
1533                                     }
1534                                 }
1535                             }
1536
1537                             // update the pointers incase they have been moved
1538                             rot_next = ar.anim.joints[jpos].rotationkeys[state.nextkeyframe_rot];
1539                             rot_last = ar.anim.joints[jpos].rotationkeys[state.lastkeyframe_rot];
1540
1541                             // TODO the lerp/delta is faulty
1542                             // it is not going to handle loop points when we wrap around as last will be > next
1543                             // it also fails when currenttime < last_time which occurs as keyframe[0] is not exactly at
1544                             // t(0).
1545                             float delta = state.currenttime_rot - rot_last.time / (rot_next.time - rot_last.time);
1546                             delta = Utils.Clamp(delta, 0f, 1f);
1547                             Vector3 rotlerpv = Vector3.Lerp(rot_last.key_element, rot_next.key_element, delta);
1548                             // rotlerp = Quaternion.Slerp(Quaternion.Identity,new Quaternion(rotlerpv.X, rotlerpv.Y, rotlerpv.Z), factor);
1549
1550                             if (easeoutset == false && ar.playstate == animationwrapper.animstate.STATE_EASEOUT)
1551                             {
1552                                 easeoutset = true;
1553                                 state.easeoutrot = new Quaternion(rotlerpv.X, rotlerpv.Y, rotlerpv.Z);
1554                                 state.easeoutfactor = factor;
1555                             }
1556                             else
1557                             {
1558                                 rotlerp = new Quaternion(rotlerpv.X, rotlerpv.Y, rotlerpv.Z);
1559                             }
1560                         }
1561
1562                         //end of rotation
1563
1564                         joint jointstate = new Rendering.joint();
1565
1566                         if (jointdeforms.TryGetValue(ar.anim.joints[jpos].Name, out jointstate))
1567                         {
1568                             jointstate.offset += (poslerp);
1569
1570                             if (ar.playstate != animationwrapper.animstate.STATE_EASEOUT)
1571                             {
1572                                 if (easeoutset == true)
1573                                 {
1574                                     jointstate.rotation = Quaternion.Slerp(jointstate.rotation, state.easeoutrot, state.easeoutfactor);
1575                                 }
1576                                 else
1577                                 {
1578                                     jointstate.rotation = rotlerp;
1579                                 }
1580                             }
1581
1582                             //jointstate.rotation= Quaternion.Slerp(jointstate.rotation, rotlerp, 0.5f);
1583                         }
1584                         else
1585                         {
1586                             jointstate = new joint();
1587                             jointstate.rotation = rotlerp;
1588                             jointstate.offset = poslerp;
1589                             jointdeforms.Add(ar.anim.joints[jpos].Name, jointstate);
1590                         }
1591
1592                         //warning struct copy non reference
1593                         ar.anim.joints[jpos].Tag = state;
1594
1595                         jpos++;
1596                     }
1597                 }
1598             }
1599
1600             foreach (KeyValuePair<string, joint> kvp in jointdeforms)
1601             {
1602                 deformbone(kvp.Key, kvp.Value.offset, kvp.Value.rotation);
1603             }
1604             mNeedsMeshRebuild = true;
1605         }
1606
1607     }
1608
1609     public class Bone
1610     {
1611         public string name;
1612         public Vector3 pos;
1613         public Quaternion rot;
1614         public Vector3 scale;
1615         public Vector3 piviot;
1616
1617         public Vector3 offset_pos;
1618
1619         public Vector3 orig_pos;
1620         public Quaternion orig_rot;
1621         public Vector3 orig_scale;
1622         public Vector3 orig_piviot;
1623
1624         Matrix4 mDeformMatrix = Matrix4.Identity;
1625
1626         public Vector3 animation_offset;
1627
1628         public Bone parent;
1629
1630         public List<Bone> children = new List<Bone>();
1631
1632         public static Dictionary<string, Bone> mBones = new Dictionary<string, Bone>();
1633         public static Dictionary<int, Bone> mIndexedBones = new Dictionary<int, Bone>();
1634         static int boneaddindex = 0;
1635
1636         private bool rotdirty = true;
1637         private bool posdirty = true;
1638
1639         //Inverse bind matrix with bone scale
1640         private Vector3 mTotalPos;
1641
1642         private Quaternion mTotalRot;
1643
1644         private Vector3 mDeltaPos;
1645         private Quaternion mDeltaRot;
1646
1647         public string mParentBone = null;
1648
1649         public Bone()
1650         {
1651         }
1652
1653         public Bone(Bone source)
1654         {
1655             name = String.Copy(source.name);
1656             pos = new Vector3(source.pos);
1657             rot = new Quaternion(source.rot);
1658             scale = new Vector3(source.scale);
1659             piviot = new Vector3(source.piviot);
1660             offset_pos = new Vector3(source.offset_pos);
1661
1662             orig_piviot = source.orig_piviot;
1663             orig_pos = source.orig_pos;
1664             orig_rot = source.orig_rot;
1665             orig_scale = source.orig_scale;
1666
1667             mParentBone = source.mParentBone;
1668
1669             mDeformMatrix = new Matrix4(source.mDeformMatrix);
1670         }
1671
1672         public static void loadbones(string skeletonfilename)
1673         {
1674             lock (Bone.mBones) mBones.Clear();
1675             string basedir = Directory.GetCurrentDirectory() + System.IO.Path.DirectorySeparatorChar + "character" + System.IO.Path.DirectorySeparatorChar;
1676             XmlDocument skeleton = new XmlDocument();
1677             skeleton.Load(basedir + skeletonfilename);
1678             XmlNode boneslist = skeleton.GetElementsByTagName("linden_skeleton")[0];
1679             addbone(boneslist.ChildNodes[0], null);
1680         }
1681
1682         public static void addbone(XmlNode bone, Bone parent)
1683         {
1684
1685             if (bone.Name != "bone")
1686                 return;
1687
1688             Bone b = new Bone();
1689             b.name = bone.Attributes.GetNamedItem("name").Value;
1690
1691             string pos = bone.Attributes.GetNamedItem("pos").Value;
1692             string[] posparts = pos.Split(' ');
1693             b.pos = new Vector3(float.Parse(posparts[0], Utils.EnUsCulture), float.Parse(posparts[1], Utils.EnUsCulture), float.Parse(posparts[2], Utils.EnUsCulture));
1694             b.orig_pos = new Vector3(b.pos);
1695             b.offset_pos = new Vector3(b.pos);
1696
1697             string rot = bone.Attributes.GetNamedItem("rot").Value;
1698             string[] rotparts = rot.Split(' ');
1699             b.rot = Quaternion.CreateFromEulers((float)(float.Parse(rotparts[0], Utils.EnUsCulture) * Math.PI / 180f), (float)(float.Parse(rotparts[1], Utils.EnUsCulture) * Math.PI / 180f), (float)(float.Parse(rotparts[2], Utils.EnUsCulture) * Math.PI / 180f));
1700             b.orig_rot = new Quaternion(b.rot);
1701
1702             string scale = bone.Attributes.GetNamedItem("scale").Value;
1703             string[] scaleparts = scale.Split(' ');
1704             b.scale = new Vector3(float.Parse(scaleparts[0], Utils.EnUsCulture), float.Parse(scaleparts[1], Utils.EnUsCulture), float.Parse(scaleparts[2], Utils.EnUsCulture));
1705             b.orig_scale = new Vector3(b.scale);
1706
1707
1708             float[] deform = Math3D.CreateSRTMatrix(new Vector3(1, 1, 1), b.rot, b.orig_pos);
1709             b.mDeformMatrix = new Matrix4(deform[0], deform[1], deform[2], deform[3], deform[4], deform[5], deform[6], deform[7], deform[8], deform[9], deform[10], deform[11], deform[12], deform[13], deform[14], deform[15]);
1710
1711             //TODO piviot
1712
1713             b.parent = parent;
1714             if (parent != null)
1715             {
1716                 b.mParentBone = parent.name;
1717                 parent.children.Add(b);
1718             }
1719
1720             lock (Bone.mBones) mBones.Add(b.name, b);
1721             mIndexedBones.Add(boneaddindex++, b);
1722
1723             Logger.Log("Found bone " + b.name, Helpers.LogLevel.Info);
1724
1725             foreach (XmlNode childbone in bone.ChildNodes)
1726             {
1727                 addbone(childbone, b);
1728             }
1729
1730         }
1731
1732         public void deformbone(Vector3 dpos, Quaternion rot)
1733         {
1734             //float[] deform = Math3D.CreateSRTMatrix(scale, rot, this.orig_pos);
1735             //mDeformMatrix = new Matrix4(deform[0], deform[1], deform[2], deform[3], deform[4], deform[5], deform[6], deform[7], deform[8], deform[9], deform[10], deform[11], deform[12], deform[13], deform[14], deform[15]);
1736
1737             //this.offset_pos += pos;
1738             //this.pos = pos;
1739             // this.offset_pos = pos;
1740
1741             animation_offset = dpos;
1742
1743             //this.pos = Bone.mBones[name].offset_pos + dpos;
1744             lock (Bone.mBones) this.rot = Bone.mBones[name].orig_rot * rot;
1745
1746             markdirty();
1747         }
1748
1749         public void scalebone(Vector3 scale)
1750         {
1751             this.scale *= scale;
1752             markdirty();
1753         }
1754
1755         public void offsetbone(Vector3 offset)
1756         {
1757             this.offset_pos += offset;
1758             markdirty();
1759         }
1760
1761         // If we deform a bone mark this bone and all its children as dirty.  
1762         public void markdirty()
1763         {
1764             rotdirty = true;
1765             posdirty = true;
1766             foreach (Bone childbone in children)
1767             {
1768                 childbone.markdirty();
1769             }
1770         }
1771
1772         public Matrix4 getdeform()
1773         {
1774             if (this.parent != null)
1775             {
1776                 return mDeformMatrix * parent.getdeform();
1777             }
1778             else
1779             {
1780                 return mDeformMatrix;
1781             }
1782         }
1783
1784         private Vector3 getOffset()
1785         {
1786             if (parent != null)
1787             {
1788                 Quaternion totalrot = getParentRot(); // we don't want this joints rotation included
1789                 Vector3 parento = parent.getOffset();
1790                 mTotalPos = parento + pos * parent.scale * totalrot;
1791                 Vector3 orig = getOrigOffset();
1792                 mDeltaPos = mTotalPos - orig;
1793
1794                 posdirty = false;
1795
1796                 return mTotalPos;
1797             }
1798             else
1799             {
1800                 Vector3 orig = getOrigOffset();
1801                 //mTotalPos = (pos * scale)+offset_pos;
1802                 //mTotalPos = (pos) + offset_pos;
1803                 mTotalPos = pos;
1804                 mDeltaPos = mTotalPos - orig;
1805                 posdirty = false;
1806                 return mTotalPos;
1807
1808             }
1809         }
1810
1811         public Vector3 getMyOffset()
1812         {
1813             return pos * scale;
1814         }
1815
1816         // Try to save some cycles by not recalculating positions and rotations every time
1817         public Vector3 getTotalOffset()
1818         {
1819             if (posdirty == false)
1820             {
1821                 return mTotalPos;
1822             }
1823             else
1824             {
1825                 return getOffset();
1826             }
1827         }
1828
1829         public Vector3 getDeltaOffset()
1830         {
1831             if (posdirty == false)
1832             {
1833                 return mDeltaPos;
1834             }
1835             else
1836             {
1837                 getOffset();
1838                 return mDeltaPos;
1839             }
1840         }
1841
1842         private Vector3 getOrigOffset()
1843         {
1844             if (parent != null)
1845             {
1846                 return (parent.getOrigOffset() + orig_pos);
1847             }
1848             else
1849             {
1850                 return orig_pos;
1851             }
1852         }
1853
1854         private static Quaternion getRotation(string bonename)
1855         {
1856             Bone b;
1857             lock (Bone.mBones)
1858             {
1859                 if (mBones.TryGetValue(bonename, out b))
1860                 {
1861                     return (b.getRotation());
1862                 }
1863                 else
1864                 {
1865                     return Quaternion.Identity;
1866                 }
1867             }
1868         }
1869
1870
1871         private Quaternion getParentRot()
1872         {
1873             Quaternion totalrot = Quaternion.Identity;
1874
1875             if (parent != null)
1876             {
1877                 totalrot = parent.getRotation();
1878             }
1879
1880             return totalrot;
1881
1882         }
1883
1884         private Quaternion getRotation()
1885         {
1886             Quaternion totalrot = rot;
1887
1888             if (parent != null)
1889             {
1890                 totalrot = parent.getRotation() * rot;
1891             }
1892
1893             mTotalRot = totalrot;
1894             rotdirty = false;
1895
1896             return totalrot;
1897         }
1898
1899         public Quaternion getTotalRotation()
1900         {
1901             if (rotdirty == false)
1902             {
1903                 return mTotalRot;
1904             }
1905             else
1906             {
1907                 return getRotation();
1908             }
1909         }
1910     }
1911
1912     public class BoneDeform
1913     {
1914         public BoneDeform(Vector3 scale, Vector3 offset)
1915         {
1916             this.scale = scale;
1917             this.offset = offset;
1918         }
1919
1920         public Vector3 scale;
1921         public Vector3 offset;
1922     }
1923
1924     public class VisualParamEx
1925     {
1926         //All visual params indexed by ID
1927         static public Dictionary<int, VisualParamEx> allParams = new Dictionary<int, VisualParamEx>();
1928
1929         // The sorted list of tweakable params, this matches the AvatarAppearance packet visual
1930         // parameters ordering
1931         static public SortedList tweakable_params = new SortedList();
1932
1933         public Dictionary<string, BoneDeform> BoneDeforms = null;
1934
1935         public Dictionary<string, VolumeDeform> VolumeDeforms = null;
1936
1937         public List<driven> childparams = null;
1938
1939         public List<VisualParamEx> identicalIds = new List<VisualParamEx>();
1940
1941         public string morphmesh = null;
1942
1943         enum GroupType
1944         {
1945             VISUAL_PARAM_GROUP_TWEAKABLE = 0,
1946             VISUAL_PARAM_GROUP_ANIMATABLE,
1947             VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT,
1948         }
1949
1950         public struct VolumeDeform
1951         {
1952             public string name;
1953             public Vector3 scale;
1954             public Vector3 pos;
1955         }
1956
1957         public enum EparamSex
1958         {
1959             SEX_BOTH = 0,
1960             SEX_FEMALE = 1,
1961             SEX_MALE = 2
1962         }
1963
1964         public enum ParamType
1965         {
1966             TYPE_NOTSET = 0,
1967             TYPE_BONEDEFORM,
1968             TYPE_MORPH,
1969             TYPE_DRIVER,
1970             TYPE_COLOR,
1971             TYPE_LAYER
1972         }
1973
1974         public struct driven
1975         {
1976             public int id;
1977             public float max1;
1978             public float max2;
1979             public float min1;
1980             public float min2;
1981             public bool hasMinMax;
1982         }
1983
1984         public string meshname;
1985
1986         /// <summary>Index of this visual param</summary>
1987         public int ParamID;
1988         /// <summary>Internal name</summary>
1989         public string Name;
1990         /// <summary>Group ID this parameter belongs to</summary>
1991         public int Group;
1992         /// <summary>Name of the wearable this parameter belongs to</summary>
1993         public string Wearable;
1994         /// <summary>Displayable label of this characteristic</summary>
1995         public string Label;
1996         /// <summary>Displayable label for the minimum value of this characteristic</summary>
1997         public string LabelMin;
1998         /// <summary>Displayable label for the maximum value of this characteristic</summary>
1999         public string LabelMax;
2000         /// <summary>Default value</summary>
2001         public float DefaultValue;
2002         /// <summary>Minimum value</summary>
2003         public float MinValue;
2004         /// <summary>Maximum value</summary>
2005         public float MaxValue;
2006         /// <summary>Is this param used for creation of bump layer?</summary>
2007         public bool IsBumpAttribute;
2008         /// <summary>Alpha blending/bump info</summary>
2009         public VisualAlphaParam? AlphaParams;
2010         /// <summary>Color information</summary>
2011         public VisualColorParam? ColorParams;
2012         /// <summary>Array of param IDs that are drivers for this parameter</summary>
2013         public int[] Drivers;
2014         /// <summary>The Avatar Sex that this parameter applies to</summary>
2015         public EparamSex sex;
2016
2017         public ParamType pType;
2018
2019         public static int count = 0;
2020
2021         /// <summary>
2022         /// Set all the values through the constructor
2023         /// </summary>
2024         /// <param name="paramID">Index of this visual param</param>
2025         /// <param name="name">Internal name</param>
2026         /// <param name="group"></param>
2027         /// <param name="wearable"></param>
2028         /// <param name="label">Displayable label of this characteristic</param>
2029         /// <param name="labelMin">Displayable label for the minimum value of this characteristic</param>
2030         /// <param name="labelMax">Displayable label for the maximum value of this characteristic</param>
2031         /// <param name="def">Default value</param>
2032         /// <param name="min">Minimum value</param>
2033         /// <param name="max">Maximum value</param>
2034         /// <param name="isBumpAttribute">Is this param used for creation of bump layer?</param>
2035         /// <param name="drivers">Array of param IDs that are drivers for this parameter</param>
2036         /// <param name="alpha">Alpha blending/bump info</param>
2037         /// <param name="colorParams">Color information</param>
2038         public VisualParamEx(int paramID, string name, int group, string wearable, string label, string labelMin, string labelMax, float def, float min, float max, bool isBumpAttribute, int[] drivers, VisualAlphaParam? alpha, VisualColorParam? colorParams)
2039         {
2040             ParamID = paramID;
2041             Name = name;
2042             Group = group;
2043             Wearable = wearable;
2044             Label = label;
2045             LabelMin = labelMin;
2046             LabelMax = labelMax;
2047             DefaultValue = def;
2048             MaxValue = max;
2049             MinValue = min;
2050             IsBumpAttribute = isBumpAttribute;
2051             Drivers = drivers;
2052             AlphaParams = alpha;
2053             ColorParams = colorParams;
2054             sex = EparamSex.SEX_BOTH;
2055         }
2056
2057         public bool matchchildnode(string test, XmlNode node)
2058         {
2059             foreach (XmlNode n in node.ChildNodes)
2060             {
2061                 if (n.Name == test)
2062                     return true;
2063             }
2064
2065             return false;
2066         }
2067
2068         public VisualParamEx(XmlNode node)
2069         {
2070
2071             ParamID = Int32.Parse(node.Attributes.GetNamedItem("id").Value);
2072             Name = node.Attributes.GetNamedItem("name").Value;
2073             Group = Int32.Parse(node.Attributes.GetNamedItem("group").Value);
2074
2075             //These dont exist for facal expresion morphs
2076             if (node.Attributes.GetNamedItem("wearable") != null)
2077                 Wearable = node.Attributes.GetNamedItem("wearable").Value;
2078
2079             MinValue = float.Parse(node.Attributes.GetNamedItem("value_min").Value, Utils.EnUsCulture);
2080             MaxValue = float.Parse(node.Attributes.GetNamedItem("value_max").Value, Utils.EnUsCulture);
2081
2082             // These do not exists for driven parameters
2083             if (node.Attributes.GetNamedItem("label_min") != null)
2084             {
2085                 LabelMin = node.Attributes.GetNamedItem("label_min").Value;
2086             }
2087
2088             if (node.Attributes.GetNamedItem("label_max") != null)
2089             {
2090                 LabelMax = node.Attributes.GetNamedItem("label_max").Value;
2091             }
2092
2093             XmlNode sexnode = node.Attributes.GetNamedItem("sex");
2094
2095             if (sexnode != null)
2096             {
2097                 if (sexnode.Value == "male")
2098                 {
2099                     sex = EparamSex.SEX_MALE;
2100                 }
2101                 else
2102                 {
2103                     sex = EparamSex.SEX_FEMALE;
2104                 }
2105             }
2106
2107             if (node.ParentNode.Name == "mesh")
2108             {
2109                 this.morphmesh = node.ParentNode.Attributes.GetNamedItem("type").Value;
2110             }
2111
2112             Group = int.Parse(node.Attributes.GetNamedItem("group").Value);
2113
2114             if (Group == (int)GroupType.VISUAL_PARAM_GROUP_TWEAKABLE)
2115             {
2116                 if (!tweakable_params.ContainsKey(ParamID)) //stupid duplicate shared params
2117                 {
2118                     tweakable_params.Add(this.ParamID, this);
2119                 }
2120                 else
2121                 {
2122                     Logger.Log(String.Format("Warning duplicate tweakable paramater ID {0} {1}", count, this.Name), Helpers.LogLevel.Warning);
2123                 }
2124                 count++;
2125             }
2126
2127             if (allParams.ContainsKey(ParamID))
2128             {
2129                 //Logger.Log("Shared VisualParam id " + ParamID.ToString() + " "+Name, Helpers.LogLevel.Info);
2130                 allParams[ParamID].identicalIds.Add(this);
2131             }
2132             else
2133             {
2134                 //Logger.Log("VisualParam id " + ParamID.ToString() + " " + Name, Helpers.LogLevel.Info);
2135                 allParams.Add(ParamID, this);
2136             }
2137
2138             if (matchchildnode("param_skeleton", node))
2139             {
2140                 pType = ParamType.TYPE_BONEDEFORM;
2141                 // If we are in the skeleton section then we also have bone deforms to parse
2142                 BoneDeforms = new Dictionary<string, BoneDeform>();
2143                 if (node.HasChildNodes && node.ChildNodes[0].HasChildNodes)
2144                 {
2145                     ParseBoneDeforms(node.ChildNodes[0].ChildNodes);
2146                 }
2147             }
2148
2149             if (matchchildnode("param_morph", node))
2150             {
2151                 pType = ParamType.TYPE_MORPH;
2152
2153                 VolumeDeforms = new Dictionary<string, VolumeDeform>();
2154                 if (node.HasChildNodes && node.ChildNodes[0].HasChildNodes)
2155                 {
2156                     ParseVolumeDeforms(node.ChildNodes[0].ChildNodes);
2157                 }
2158             }
2159
2160             if (matchchildnode("param_driver", node))
2161             {
2162                 pType = ParamType.TYPE_DRIVER;
2163                 childparams = new List<driven>();
2164                 if (node.HasChildNodes && node.ChildNodes[0].HasChildNodes) //LAZY
2165                 {
2166                     ParseDrivers(node.ChildNodes[0].ChildNodes);
2167                 }
2168             }
2169
2170             if (matchchildnode("param_color", node))
2171             {
2172                 pType = ParamType.TYPE_COLOR;
2173                 if (node.HasChildNodes)
2174                 {
2175                     foreach (XmlNode colorchild in node.ChildNodes)
2176                     {
2177                         if (colorchild.Name == "param_color")
2178                         {
2179                             //TODO extract <value color="50, 25, 5, 255" />
2180                         }
2181                     }
2182                 }
2183             }
2184
2185         }
2186
2187         void ParseBoneDeforms(XmlNodeList deforms)
2188         {
2189             foreach (XmlNode node in deforms)
2190             {
2191                 if (node.Name == "bone")
2192                 {
2193                     string name = node.Attributes.GetNamedItem("name").Value;
2194                     Vector3 scale = Vector3.One;
2195                     Vector3 offset = Vector3.One;
2196
2197                     if (node.Attributes.GetNamedItem("scale") != null)
2198                         scale = XmlParseVector(node.Attributes.GetNamedItem("scale").Value);
2199
2200                     if (node.Attributes.GetNamedItem("offset") != null)
2201                         offset = XmlParseVector(node.Attributes.GetNamedItem("offset").Value);
2202
2203                     BoneDeform bd = new BoneDeform(scale, offset);
2204
2205                     BoneDeforms.Add(name, bd);
2206                 }
2207             }
2208         }
2209
2210         void ParseVolumeDeforms(XmlNodeList deforms)
2211         {
2212             foreach (XmlNode node in deforms)
2213             {
2214                 if (node.Name == "volume_morph")
2215                 {
2216                     VolumeDeform vd = new VolumeDeform();
2217                     vd.name = node.Attributes.GetNamedItem("name").Value;
2218                     vd.name = vd.name.ToLower();
2219
2220                     if (node.Attributes.GetNamedItem("scale") != null)
2221                     {
2222                         vd.scale = XmlParseVector(node.Attributes.GetNamedItem("scale").Value);
2223                     }
2224                     else
2225                     {
2226                         vd.scale = new Vector3(0, 0, 0);
2227                     }
2228
2229                     if (node.Attributes.GetNamedItem("pos") != null)
2230                     {
2231                         vd.pos = XmlParseVector(node.Attributes.GetNamedItem("pos").Value);
2232                     }
2233                     else
2234                     {
2235                         vd.pos = new Vector3(0f, 0f, 0f);
2236                     }
2237
2238                     VolumeDeforms.Add(vd.name, vd);
2239                 }
2240             }
2241         }
2242
2243         void ParseDrivers(XmlNodeList drivennodes)
2244         {
2245             foreach (XmlNode node in drivennodes)
2246             {
2247                 if (node.Name == "driven")
2248                 {
2249                     driven d = new driven();
2250
2251                     d.id = Int32.Parse(node.Attributes.GetNamedItem("id").Value);
2252                     XmlNode param = node.Attributes.GetNamedItem("max1");
2253                     if (param != null)
2254                     {
2255                         d.max1 = float.Parse(param.Value, Utils.EnUsCulture);
2256                         d.max2 = float.Parse(node.Attributes.GetNamedItem("max2").Value, Utils.EnUsCulture);
2257                         d.min1 = float.Parse(node.Attributes.GetNamedItem("min1").Value, Utils.EnUsCulture);
2258                         d.min2 = float.Parse(node.Attributes.GetNamedItem("min2").Value, Utils.EnUsCulture);
2259                         d.hasMinMax = true;
2260                     }
2261                     else
2262                     {
2263                         d.hasMinMax = false;
2264                     }
2265
2266                     childparams.Add(d);
2267
2268                 }
2269             }
2270         }
2271
2272         public static Vector3 XmlParseVector(string data)
2273         {
2274             string[] posparts = data.Split(' ');
2275             return new Vector3(float.Parse(posparts[0], Utils.EnUsCulture), float.Parse(posparts[1], Utils.EnUsCulture), float.Parse(posparts[2], Utils.EnUsCulture));
2276         }
2277
2278         public static Quaternion XmlParseRotation(string data)
2279         {
2280             string[] rotparts = data.Split(' ');
2281             return Quaternion.CreateFromEulers((float)(float.Parse(rotparts[0]) * Math.PI / 180f), (float)(float.Parse(rotparts[1]) * Math.PI / 180f), (float)(float.Parse(rotparts[2]) * Math.PI / 180f));
2282         }
2283     }
2284
2285     public class RenderAvatar : SceneObject
2286     {
2287         public static Dictionary<int, string> BakedTextures = new Dictionary<int, string>
2288             {
2289                 { 8, "head" },
2290                 { 9, "upper" },
2291                 { 10, "lower" },
2292                 { 11, "eyes" },
2293                 { 19, "skirt" },
2294                 { 20, "hair" }
2295             };
2296
2297         public GLAvatar glavatar = new GLAvatar();
2298         public Avatar avatar;
2299         public FaceData[] data = new FaceData[32];
2300         public Dictionary<UUID, Animation> animlist = new Dictionary<UUID, Animation>();
2301         public Dictionary<WearableType, AppearanceManager.WearableData> Wearables = new Dictionary<WearableType, AppearanceManager.WearableData>();
2302         public static readonly BoundingVolume AvatarBoundingVolume;
2303
2304         // Static constructor
2305         static RenderAvatar()
2306         {
2307             AvatarBoundingVolume = new BoundingVolume();
2308             AvatarBoundingVolume.FromScale(Vector3.One);
2309         }
2310
2311         // Default constructor
2312         public RenderAvatar()
2313         {
2314             BoundingVolume = AvatarBoundingVolume;
2315             Type = SceneObjectType.Avatar;
2316         }
2317
2318         public override Primitive BasePrim
2319         {
2320             get { return avatar; }
2321             set
2322             {
2323                 if (value is Avatar)
2324                 {
2325                     avatar = (Avatar)value;
2326                     AvatarBoundingVolume.CalcScaled(avatar.Scale);
2327                 }
2328             }
2329         }
2330
2331         public override void Step(float time)
2332         {
2333             glavatar.skel.animate(time);
2334             base.Step(time);
2335         }
2336
2337         public float Height;
2338         public float PelvisToFoot;
2339
2340         public void UpdateSize()
2341         {
2342             float F_SQRT2 = 1.4142135623730950488016887242097f;
2343
2344             Vector3 pelvis_scale = glavatar.skel.mBones["mPelvis"].scale;
2345
2346             Vector3 skull = glavatar.skel.mBones["mSkull"].pos;
2347             Vector3 skull_scale = glavatar.skel.mBones["mSkull"].scale;
2348
2349             Vector3 neck = glavatar.skel.mBones["mNeck"].pos;
2350             Vector3 neck_scale = glavatar.skel.mBones["mNeck"].scale;
2351
2352             Vector3 chest = glavatar.skel.mBones["mChest"].pos;
2353             Vector3 chest_scale = glavatar.skel.mBones["mChest"].scale;
2354
2355             Vector3 head = glavatar.skel.mBones["mHead"].pos;
2356             Vector3 head_scale = glavatar.skel.mBones["mHead"].scale;
2357
2358             Vector3 torso = glavatar.skel.mBones["mTorso"].pos;
2359             Vector3 torso_scale = glavatar.skel.mBones["mTorso"].scale;
2360
2361             Vector3 hip = glavatar.skel.mBones["mHipLeft"].pos;
2362             Vector3 hip_scale = glavatar.skel.mBones["mHipLeft"].scale;
2363
2364             Vector3 knee = glavatar.skel.mBones["mKneeLeft"].pos;
2365             Vector3 knee_scale = glavatar.skel.mBones["mKneeLeft"].scale;
2366
2367             Vector3 ankle = glavatar.skel.mBones["mAnkleLeft"].pos;
2368             Vector3 ankle_scale = glavatar.skel.mBones["mAnkleLeft"].scale;
2369
2370             Vector3 foot = glavatar.skel.mBones["mFootLeft"].pos;
2371
2372             // mAvatarOffset.Z = getVisualParamWeight(11001);
2373
2374             float mPelvisToFoot = hip.Z * pelvis_scale.Z -
2375                             knee.Z * hip_scale.Z -
2376                             ankle.Z * knee_scale.Z -
2377                             foot.Z * ankle_scale.Z;
2378
2379             Vector3 new_body_size;
2380             new_body_size.Z = mPelvisToFoot +
2381                 // the sqrt(2) correction below is an approximate
2382                 // correction to get to the top of the head
2383                                F_SQRT2 * (skull.Z * head_scale.Z) +
2384                                head.Z * neck_scale.Z +
2385                                neck.Z * chest_scale.Z +
2386                                chest.Z * torso_scale.Z +
2387                                torso.Z * pelvis_scale.Z;
2388
2389             Height = new_body_size.Z;
2390             PelvisToFoot = mPelvisToFoot;
2391         }
2392
2393         public Vector3 AdjustedPosition(Vector3 source)
2394         {
2395             return new Vector3(source.X, source.Y, source.Z - Height + PelvisToFoot);
2396         }
2397     }
2398 }