OSDN Git Service

f3e84378151c1bc1ec8a29d36235d4bd6c21ddde
[radegast/radegast.git] / Radegast / GUI / Rendering / RenderingHelpers.cs
1 using System;\r
2 using System.Collections.Generic;\r
3 using System.Collections;\r
4 using System.Linq;\r
5 using System.Text;\r
6 using System.IO;\r
7 using System.Xml;\r
8 using System.Threading;\r
9 using OpenTK.Graphics.OpenGL;\r
10 using System.Runtime.InteropServices;\r
11 using OpenMetaverse;\r
12 using OpenMetaverse.Rendering;\r
13 \r
14 namespace Radegast.Rendering\r
15 {\r
16     public class FaceData\r
17     {\r
18         public float[] Vertices;\r
19         public ushort[] Indices;\r
20         public float[] TexCoords;\r
21         public float[] Normals;\r
22         public int PickingID = -1;\r
23         public int VertexVBO = -1;\r
24         public int IndexVBO = -1;\r
25         public TextureInfo TextureInfo = new TextureInfo();\r
26         public BoundingVolume BoundingVolume = new BoundingVolume();\r
27         public static int VertexSize = 32; // sizeof (vertex), 2  x vector3 + 1 x vector2 = 8 floats x 4 bytes = 32 bytes \r
28         public TextureAnimationInfo AnimInfo;\r
29         public int QueryID = 0;\r
30 \r
31         public void CheckVBO(Face face)\r
32         {\r
33             if (VertexVBO == -1)\r
34             {\r
35                 Vertex[] vArray = face.Vertices.ToArray();\r
36                 GL.GenBuffers(1, out VertexVBO);\r
37                 GL.BindBuffer(BufferTarget.ArrayBuffer, VertexVBO);\r
38                 GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vArray.Length * VertexSize), vArray, BufferUsageHint.StaticDraw);\r
39             }\r
40 \r
41             if (IndexVBO == -1)\r
42             {\r
43                 ushort[] iArray = face.Indices.ToArray();\r
44                 GL.GenBuffers(1, out IndexVBO);\r
45                 GL.BindBuffer(BufferTarget.ElementArrayBuffer, IndexVBO);\r
46                 GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(iArray.Length * sizeof(ushort)), iArray, BufferUsageHint.StaticDraw);\r
47             }\r
48         }\r
49     }\r
50 \r
51     public class TextureAnimationInfo\r
52     {\r
53         public Primitive.TextureAnimation PrimAnimInfo;\r
54         public float CurrentFrame;\r
55         public double CurrentTime;\r
56         public bool PingPong;\r
57         float LastTime = 0f;\r
58         float TotalTime = 0f;\r
59 \r
60         public void Step(double lastFrameTime)\r
61         {\r
62             float numFrames = 1f;\r
63             float fullLength = 1f;\r
64 \r
65             if (PrimAnimInfo.Length > 0)\r
66             {\r
67                 numFrames = PrimAnimInfo.Length;\r
68             }\r
69             else\r
70             {\r
71                 numFrames = Math.Max(1f, (float)(PrimAnimInfo.SizeX * PrimAnimInfo.SizeY));\r
72             }\r
73 \r
74             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.PING_PONG) != 0)\r
75             {\r
76                 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)\r
77                 {\r
78                     fullLength = 2f * numFrames;\r
79                 }\r
80                 else if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.LOOP) != 0)\r
81                 {\r
82                     fullLength = 2f * numFrames - 2f;\r
83                     fullLength = Math.Max(1f, fullLength);\r
84                 }\r
85                 else\r
86                 {\r
87                     fullLength = 2f * numFrames - 1f;\r
88                     fullLength = Math.Max(1f, fullLength);\r
89                 }\r
90             }\r
91             else\r
92             {\r
93                 fullLength = numFrames;\r
94             }\r
95 \r
96             float frameCounter;\r
97             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)\r
98             {\r
99                 frameCounter = (float)lastFrameTime * PrimAnimInfo.Rate + LastTime;\r
100             }\r
101             else\r
102             {\r
103                 TotalTime += (float)lastFrameTime;\r
104                 frameCounter = TotalTime * PrimAnimInfo.Rate;\r
105             }\r
106             LastTime = frameCounter;\r
107 \r
108             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.LOOP) != 0)\r
109             {\r
110                 frameCounter %= fullLength;\r
111             }\r
112             else\r
113             {\r
114                 frameCounter = Math.Min(fullLength - 1f, frameCounter);\r
115             }\r
116 \r
117             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) == 0)\r
118             {\r
119                 frameCounter = (float)Math.Floor(frameCounter + 0.01f);\r
120             }\r
121 \r
122             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.PING_PONG) != 0)\r
123             {\r
124                 if (frameCounter > numFrames)\r
125                 {\r
126                     if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)\r
127                     {\r
128                         frameCounter = numFrames - (frameCounter - numFrames);\r
129                     }\r
130                     else\r
131                     {\r
132                         frameCounter = (numFrames - 1.99f) - (frameCounter - numFrames);\r
133                     }\r
134                 }\r
135             }\r
136 \r
137             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.REVERSE) != 0)\r
138             {\r
139                 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)\r
140                 {\r
141                     frameCounter = numFrames - frameCounter;\r
142                 }\r
143                 else\r
144                 {\r
145                     frameCounter = (numFrames - 0.99f) - frameCounter;\r
146                 }\r
147             }\r
148 \r
149             frameCounter += PrimAnimInfo.Start;\r
150 \r
151             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) == 0)\r
152             {\r
153                 frameCounter = (float)Math.Round(frameCounter);\r
154             }\r
155 \r
156 \r
157             GL.MatrixMode(MatrixMode.Texture);\r
158             GL.LoadIdentity();\r
159 \r
160             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.ROTATE) != 0)\r
161             {\r
162                 GL.Translate(0.5f, 0.5f, 0f);\r
163                 GL.Rotate(Utils.RAD_TO_DEG * frameCounter, OpenTK.Vector3d.UnitZ);\r
164                 GL.Translate(-0.5f, -0.5f, 0f);\r
165             }\r
166             else if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SCALE) != 0)\r
167             {\r
168                 GL.Scale(frameCounter, frameCounter, 0);\r
169             }\r
170             else // Translate\r
171             {\r
172                 float sizeX = Math.Max(1f, (float)PrimAnimInfo.SizeX);\r
173                 float sizeY = Math.Max(1f, (float)PrimAnimInfo.SizeY);\r
174 \r
175                 GL.Scale(1f / sizeX, 1f / sizeY, 0);\r
176                 GL.Translate(frameCounter % sizeX, Math.Floor(frameCounter / sizeY), 0);\r
177             }\r
178 \r
179             GL.MatrixMode(MatrixMode.Modelview);\r
180         }\r
181 \r
182         [Obsolete("Use Step() instead")]\r
183         public void ExperimentalStep(double time)\r
184         {\r
185             int reverseFactor = 1;\r
186             float rate = PrimAnimInfo.Rate;\r
187 \r
188             if (rate < 0)\r
189             {\r
190                 rate = -rate;\r
191                 reverseFactor = -reverseFactor;\r
192             }\r
193 \r
194             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.REVERSE) != 0)\r
195             {\r
196                 reverseFactor = -reverseFactor;\r
197             }\r
198 \r
199             CurrentTime += time;\r
200             double totalTime = 1 / rate;\r
201 \r
202             uint x = Math.Max(1, PrimAnimInfo.SizeX);\r
203             uint y = Math.Max(1, PrimAnimInfo.SizeY);\r
204             uint nrFrames = x * y;\r
205 \r
206             if (PrimAnimInfo.Length > 0 && PrimAnimInfo.Length < nrFrames)\r
207             {\r
208                 nrFrames = (uint)PrimAnimInfo.Length;\r
209             }\r
210 \r
211             GL.MatrixMode(MatrixMode.Texture);\r
212             GL.LoadIdentity();\r
213 \r
214             if (CurrentTime >= totalTime)\r
215             {\r
216                 CurrentTime = 0;\r
217                 CurrentFrame++;\r
218                 if (CurrentFrame > nrFrames) CurrentFrame = (uint)PrimAnimInfo.Start;\r
219                 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.PING_PONG) != 0)\r
220                 {\r
221                     PingPong = !PingPong;\r
222                 }\r
223             }\r
224 \r
225             float smoothOffset = 0f;\r
226 \r
227             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)\r
228             {\r
229                 smoothOffset = (float)(CurrentTime / totalTime) * reverseFactor;\r
230             }\r
231 \r
232             float f = CurrentFrame;\r
233             if (reverseFactor < 0)\r
234             {\r
235                 f = nrFrames - CurrentFrame;\r
236             }\r
237 \r
238             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.ROTATE) == 0) // not rotaating\r
239             {\r
240                 GL.Scale(1f / x, 1f / y, 0f);\r
241                 GL.Translate((f % x) + smoothOffset, f / y, 0);\r
242             }\r
243             else\r
244             {\r
245                 smoothOffset = (float)(CurrentTime * PrimAnimInfo.Rate);\r
246                 double startAngle = PrimAnimInfo.Start;\r
247                 double endAngle = PrimAnimInfo.Length;\r
248                 double angle = startAngle + (endAngle - startAngle) * smoothOffset;\r
249                 GL.Translate(0.5f, 0.5f, 0f);\r
250                 GL.Rotate(Utils.RAD_TO_DEG * angle, OpenTK.Vector3d.UnitZ);\r
251                 GL.Translate(-0.5f, -0.5f, 0f);\r
252             }\r
253 \r
254             GL.MatrixMode(MatrixMode.Modelview);\r
255         }\r
256 \r
257     }\r
258 \r
259 \r
260     public class TextureInfo\r
261     {\r
262         public System.Drawing.Image Texture;\r
263         public int TexturePointer;\r
264         public bool HasAlpha;\r
265         public bool FullAlpha;\r
266         public bool IsMask;\r
267         public UUID TextureID;\r
268     }\r
269 \r
270     public class TextureLoadItem\r
271     {\r
272         public FaceData Data;\r
273         public Primitive Prim;\r
274         public Primitive.TextureEntryFace TeFace;\r
275         public byte[] TextureData = null;\r
276     }\r
277 \r
278     public enum RenderPass\r
279     {\r
280         Picking,\r
281         Simple,\r
282         Alpha\r
283     }\r
284 \r
285     public enum SceneObjectType\r
286     {\r
287         None,\r
288         Primitive,\r
289         Avatar,\r
290     }\r
291 \r
292     public abstract class SceneObject: IComparable\r
293     {\r
294         public Vector3 SimPosition;\r
295         public Quaternion SimRotation;\r
296         public float DistanceSquared;\r
297         public BoundingVolume BoundingVolume;\r
298         public bool PositionUpdated;\r
299         public SceneObjectType Type = SceneObjectType.None;\r
300         public virtual Primitive BasePrim { get; set; }\r
301 \r
302         public virtual int CompareTo(object other)\r
303         {\r
304             SceneObject o = (SceneObject)other;\r
305             if (this.DistanceSquared < o.DistanceSquared)\r
306                 return -1;\r
307             else if (this.DistanceSquared > o.DistanceSquared)\r
308                 return 1;\r
309             else\r
310                 return 0;\r
311         }\r
312     }\r
313 \r
314     public class RenderPrimitive : SceneObject, IDisposable\r
315     {\r
316         public Primitive Prim;\r
317         public List<Face> Faces;\r
318 \r
319         public RenderPrimitive()\r
320         {\r
321             Type = SceneObjectType.Primitive;\r
322         }\r
323 \r
324         public virtual void Dispose()\r
325         {\r
326         }\r
327 \r
328         public override Primitive BasePrim\r
329         {\r
330             get { return Prim; }\r
331             set { Prim = value; }\r
332         }\r
333 \r
334         public override string ToString()\r
335         {\r
336             uint id = Prim == null ? 0 : Prim.LocalID;\r
337             double distance = Math.Sqrt(DistanceSquared);\r
338             return string.Format("LocalID: {0}, distance {0.00}", id, distance);\r
339         }\r
340     }\r
341 \r
342     public static class Render\r
343     {\r
344         public static IRendering Plugin;\r
345     }\r
346 \r
347     public static class RHelp\r
348     {\r
349         static float t1 = 0.075f;\r
350         static float t2 = t1 / 5.7f;\r
351 \r
352         public static Vector3 Smoothed1stOrder(Vector3 curPos, Vector3 targetPos, double lastFrameTime)\r
353         {\r
354             int numIterations = (int)(lastFrameTime * 100);\r
355             do\r
356             {\r
357                 curPos += (targetPos - curPos) * t1;\r
358                 numIterations--;\r
359             }\r
360             while (numIterations > 0);\r
361             if (Vector3.DistanceSquared(curPos, targetPos) < 0.000001)\r
362             {\r
363                 curPos = targetPos;\r
364             }\r
365             return curPos;\r
366         }\r
367 \r
368         public static Vector3 Smoothed2ndOrder(Vector3 curPos, Vector3 targetPos, ref Vector3 accel, double lastFrameTime)\r
369         {\r
370             int numIterations = (int)(lastFrameTime * 100);\r
371             do\r
372             {\r
373                 accel += (targetPos - accel - curPos) * t1;\r
374                 curPos += accel * t2;\r
375                 numIterations--;\r
376             }\r
377             while (numIterations > 0);\r
378             if (Vector3.DistanceSquared(curPos, targetPos) < 0.000001)\r
379             {\r
380                 curPos = targetPos;\r
381             }\r
382             return curPos;\r
383         }\r
384 \r
385         public static OpenTK.Vector2 TKVector3(Vector2 v)\r
386         {\r
387             return new OpenTK.Vector2(v.X, v.Y);\r
388         }\r
389 \r
390         public static OpenTK.Vector3 TKVector3(Vector3 v)\r
391         {\r
392             return new OpenTK.Vector3(v.X, v.Y, v.Z);\r
393         }\r
394 \r
395         public static OpenTK.Vector4 TKVector3(Vector4 v)\r
396         {\r
397             return new OpenTK.Vector4(v.X, v.Y, v.Z, v.W);\r
398         }\r
399     }\r
400 \r
401     /// <summary>\r
402     /// Represents camera object\r
403     /// </summary>\r
404     public class Camera\r
405     {\r
406         Vector3 mPosition;\r
407         Vector3 mFocalPoint;\r
408         bool mModified;\r
409 \r
410         /// <summary>Camera position</summary>\r
411         public Vector3 Position { get { return mPosition; } set { mPosition = value; Modify(); } }\r
412         /// <summary>Camera target</summary>\r
413         public Vector3 FocalPoint { get { return mFocalPoint; } set { mFocalPoint = value; Modify(); } }\r
414         /// <summary>Zoom level</summary>\r
415         public float Zoom;\r
416         /// <summary>Draw distance</summary>\r
417         public float Far;\r
418         /// <summary>Has camera been modified</summary>\r
419         public bool Modified { get { return mModified; } set { mModified = value; } }\r
420 \r
421         public double TimeToTarget = 0d;\r
422 \r
423         public Vector3 RenderPosition;\r
424         public Vector3 RenderFocalPoint;\r
425 \r
426         void Modify()\r
427         {\r
428             mModified = true;\r
429         }\r
430 \r
431         public void Step(double time)\r
432         {\r
433             if (RenderPosition != Position)\r
434             {\r
435                 RenderPosition = RHelp.Smoothed1stOrder(RenderPosition, Position, time);\r
436                 Modified = true;\r
437             }\r
438             if (RenderFocalPoint != FocalPoint)\r
439             {\r
440                 RenderFocalPoint = RHelp.Smoothed1stOrder(RenderFocalPoint, FocalPoint, time);\r
441                 Modified = true;\r
442             }\r
443         }\r
444 \r
445         [Obsolete("Use Step(), left in here for reference")]\r
446         public void Step2(double time)\r
447         {\r
448             TimeToTarget -= time;\r
449             if (TimeToTarget <= time)\r
450             {\r
451                 EndMove();\r
452                 return;\r
453             }\r
454 \r
455             mModified = true;\r
456 \r
457             float pctElapsed = (float)(time / TimeToTarget);\r
458 \r
459             if (RenderPosition != Position)\r
460             {\r
461                 float distance = Vector3.Distance(RenderPosition, Position);\r
462                 RenderPosition = Vector3.Lerp(RenderPosition, Position, (float)(distance * pctElapsed));\r
463             }\r
464 \r
465             if (RenderFocalPoint != FocalPoint)\r
466             {\r
467                 RenderFocalPoint = Interpolate(RenderFocalPoint, FocalPoint, pctElapsed);\r
468             }\r
469         }\r
470 \r
471         Vector3 Interpolate(Vector3 start, Vector3 end, float fraction)\r
472         {\r
473             float distance = Vector3.Distance(start, end);\r
474             Vector3 direction = end - start;\r
475             return start + direction * fraction;\r
476         }\r
477 \r
478         public void EndMove()\r
479         {\r
480             mModified = true;\r
481             TimeToTarget = 0;\r
482             RenderPosition = Position;\r
483             RenderFocalPoint = FocalPoint;\r
484         }\r
485     }\r
486 \r
487     public static class MeshToOBJ\r
488     {\r
489         public static bool MeshesToOBJ(Dictionary<uint, FacetedMesh> meshes, string filename)\r
490         {\r
491             StringBuilder obj = new StringBuilder();\r
492             StringBuilder mtl = new StringBuilder();\r
493 \r
494             FileInfo objFileInfo = new FileInfo(filename);\r
495 \r
496             string mtlFilename = objFileInfo.FullName.Substring(objFileInfo.DirectoryName.Length + 1,\r
497                 objFileInfo.FullName.Length - (objFileInfo.DirectoryName.Length + 1) - 4) + ".mtl";\r
498 \r
499             obj.AppendLine("# Created by libprimrender");\r
500             obj.AppendLine("mtllib ./" + mtlFilename);\r
501             obj.AppendLine();\r
502 \r
503             mtl.AppendLine("# Created by libprimrender");\r
504             mtl.AppendLine();\r
505 \r
506             int primNr = 0;\r
507             foreach (FacetedMesh mesh in meshes.Values)\r
508             {\r
509                 for (int j = 0; j < mesh.Faces.Count; j++)\r
510                 {\r
511                     Face face = mesh.Faces[j];\r
512 \r
513                     if (face.Vertices.Count > 2)\r
514                     {\r
515                         string mtlName = String.Format("material{0}-{1}", primNr, face.ID);\r
516                         Primitive.TextureEntryFace tex = face.TextureFace;\r
517                         string texName = tex.TextureID.ToString() + ".tga";\r
518 \r
519                         // FIXME: Convert the source to TGA (if needed) and copy to the destination\r
520 \r
521                         float shiny = 0.00f;\r
522                         switch (tex.Shiny)\r
523                         {\r
524                             case Shininess.High:\r
525                                 shiny = 1.00f;\r
526                                 break;\r
527                             case Shininess.Medium:\r
528                                 shiny = 0.66f;\r
529                                 break;\r
530                             case Shininess.Low:\r
531                                 shiny = 0.33f;\r
532                                 break;\r
533                         }\r
534 \r
535                         obj.AppendFormat("g face{0}-{1}{2}", primNr, face.ID, Environment.NewLine);\r
536 \r
537                         mtl.AppendLine("newmtl " + mtlName);\r
538                         mtl.AppendFormat("Ka {0} {1} {2}{3}", tex.RGBA.R, tex.RGBA.G, tex.RGBA.B, Environment.NewLine);\r
539                         mtl.AppendFormat("Kd {0} {1} {2}{3}", tex.RGBA.R, tex.RGBA.G, tex.RGBA.B, Environment.NewLine);\r
540                         //mtl.AppendFormat("Ks {0} {1} {2}{3}");\r
541                         mtl.AppendLine("Tr " + tex.RGBA.A);\r
542                         mtl.AppendLine("Ns " + shiny);\r
543                         mtl.AppendLine("illum 1");\r
544                         if (tex.TextureID != UUID.Zero && tex.TextureID != Primitive.TextureEntry.WHITE_TEXTURE)\r
545                             mtl.AppendLine("map_Kd ./" + texName);\r
546                         mtl.AppendLine();\r
547 \r
548                         // Write the vertices, texture coordinates, and vertex normals for this side\r
549                         for (int k = 0; k < face.Vertices.Count; k++)\r
550                         {\r
551                             Vertex vertex = face.Vertices[k];\r
552 \r
553                             #region Vertex\r
554 \r
555                             Vector3 pos = vertex.Position;\r
556 \r
557                             // Apply scaling\r
558                             pos *= mesh.Prim.Scale;\r
559 \r
560                             // Apply rotation\r
561                             pos *= mesh.Prim.Rotation;\r
562 \r
563                             // The root prim position is sim-relative, while child prim positions are\r
564                             // parent-relative. We want to apply parent-relative translations but not\r
565                             // sim-relative ones\r
566                             if (mesh.Prim.ParentID != 0)\r
567                                 pos += mesh.Prim.Position;\r
568 \r
569                             obj.AppendFormat("v {0} {1} {2}{3}", pos.X, pos.Y, pos.Z, Environment.NewLine);\r
570 \r
571                             #endregion Vertex\r
572 \r
573                             #region Texture Coord\r
574 \r
575                             obj.AppendFormat("vt {0} {1}{2}", vertex.TexCoord.X, vertex.TexCoord.Y,\r
576                                 Environment.NewLine);\r
577 \r
578                             #endregion Texture Coord\r
579 \r
580                             #region Vertex Normal\r
581 \r
582                             // HACK: Sometimes normals are getting set to <NaN,NaN,NaN>\r
583                             if (!Single.IsNaN(vertex.Normal.X) && !Single.IsNaN(vertex.Normal.Y) && !Single.IsNaN(vertex.Normal.Z))\r
584                                 obj.AppendFormat("vn {0} {1} {2}{3}", vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z,\r
585                                     Environment.NewLine);\r
586                             else\r
587                                 obj.AppendLine("vn 0.0 1.0 0.0");\r
588 \r
589                             #endregion Vertex Normal\r
590                         }\r
591 \r
592                         obj.AppendFormat("# {0} vertices{1}", face.Vertices.Count, Environment.NewLine);\r
593                         obj.AppendLine();\r
594                         obj.AppendLine("usemtl " + mtlName);\r
595 \r
596                         #region Elements\r
597 \r
598                         // Write all of the faces (triangles) for this side\r
599                         for (int k = 0; k < face.Indices.Count / 3; k++)\r
600                         {\r
601                             obj.AppendFormat("f -{0}/-{0}/-{0} -{1}/-{1}/-{1} -{2}/-{2}/-{2}{3}",\r
602                                 face.Vertices.Count - face.Indices[k * 3 + 0],\r
603                                 face.Vertices.Count - face.Indices[k * 3 + 1],\r
604                                 face.Vertices.Count - face.Indices[k * 3 + 2],\r
605                                 Environment.NewLine);\r
606                         }\r
607 \r
608                         obj.AppendFormat("# {0} elements{1}", face.Indices.Count / 3, Environment.NewLine);\r
609                         obj.AppendLine();\r
610 \r
611                         #endregion Elements\r
612                     }\r
613                 }\r
614                 primNr++;\r
615             }\r
616 \r
617             try\r
618             {\r
619                 File.WriteAllText(filename, obj.ToString());\r
620                 File.WriteAllText(mtlFilename, mtl.ToString());\r
621             }\r
622             catch (Exception)\r
623             {\r
624                 return false;\r
625             }\r
626 \r
627             return true;\r
628         }\r
629     }\r
630 \r
631     public static class Math3D\r
632     {\r
633         // Column-major:\r
634         // |  0  4  8 12 |\r
635         // |  1  5  9 13 |\r
636         // |  2  6 10 14 |\r
637         // |  3  7 11 15 |\r
638 \r
639         public static float[] CreateTranslationMatrix(Vector3 v)\r
640         {\r
641             float[] mat = new float[16];\r
642 \r
643             mat[12] = v.X;\r
644             mat[13] = v.Y;\r
645             mat[14] = v.Z;\r
646             mat[0] = mat[5] = mat[10] = mat[15] = 1;\r
647 \r
648             return mat;\r
649         }\r
650 \r
651         public static float[] CreateRotationMatrix(Quaternion q)\r
652         {\r
653             float[] mat = new float[16];\r
654 \r
655             // Transpose the quaternion (don't ask me why)\r
656             q.X = q.X * -1f;\r
657             q.Y = q.Y * -1f;\r
658             q.Z = q.Z * -1f;\r
659 \r
660             float x2 = q.X + q.X;\r
661             float y2 = q.Y + q.Y;\r
662             float z2 = q.Z + q.Z;\r
663             float xx = q.X * x2;\r
664             float xy = q.X * y2;\r
665             float xz = q.X * z2;\r
666             float yy = q.Y * y2;\r
667             float yz = q.Y * z2;\r
668             float zz = q.Z * z2;\r
669             float wx = q.W * x2;\r
670             float wy = q.W * y2;\r
671             float wz = q.W * z2;\r
672 \r
673             mat[0] = 1.0f - (yy + zz);\r
674             mat[1] = xy - wz;\r
675             mat[2] = xz + wy;\r
676             mat[3] = 0.0f;\r
677 \r
678             mat[4] = xy + wz;\r
679             mat[5] = 1.0f - (xx + zz);\r
680             mat[6] = yz - wx;\r
681             mat[7] = 0.0f;\r
682 \r
683             mat[8] = xz - wy;\r
684             mat[9] = yz + wx;\r
685             mat[10] = 1.0f - (xx + yy);\r
686             mat[11] = 0.0f;\r
687 \r
688             mat[12] = 0.0f;\r
689             mat[13] = 0.0f;\r
690             mat[14] = 0.0f;\r
691             mat[15] = 1.0f;\r
692 \r
693             return mat;\r
694         }\r
695 \r
696         public static float[] CreateSRTMatrix(Vector3 scale, Quaternion q, Vector3 pos)\r
697         {\r
698             float[] mat = new float[16];\r
699 \r
700             // Transpose the quaternion (don't ask me why)\r
701             q.X = q.X * -1f;\r
702             q.Y = q.Y * -1f;\r
703             q.Z = q.Z * -1f;\r
704 \r
705             float x2 = q.X + q.X;\r
706             float y2 = q.Y + q.Y;\r
707             float z2 = q.Z + q.Z;\r
708             float xx = q.X * x2;\r
709             float xy = q.X * y2;\r
710             float xz = q.X * z2;\r
711             float yy = q.Y * y2;\r
712             float yz = q.Y * z2;\r
713             float zz = q.Z * z2;\r
714             float wx = q.W * x2;\r
715             float wy = q.W * y2;\r
716             float wz = q.W * z2;\r
717 \r
718             mat[0] = (1.0f - (yy + zz))*scale.X;\r
719             mat[1] = (xy - wz)*scale.X;\r
720             mat[2] = (xz + wy) * scale.X;\r
721             mat[3] = 0.0f;\r
722 \r
723             mat[4] = (xy + wz) * scale.Y;\r
724             mat[5] = (1.0f - (xx + zz)) * scale.Y;\r
725             mat[6] = (yz - wx) * scale.Y;\r
726             mat[7] = 0.0f;\r
727 \r
728             mat[8] = (xz - wy) * scale.Z;\r
729             mat[9] = (yz + wx) * scale.Z;\r
730             mat[10] = (1.0f - (xx + yy)) * scale.Z;\r
731             mat[11] = 0.0f;\r
732 \r
733             //Positional parts\r
734             mat[12] = pos.X;\r
735             mat[13] = pos.Y;\r
736             mat[14] = pos.Z;\r
737             mat[15] = 1.0f;\r
738 \r
739             return mat;\r
740         }\r
741 \r
742 \r
743         public static float[] CreateScaleMatrix(Vector3 v)\r
744         {\r
745             float[] mat = new float[16];\r
746 \r
747             mat[0] = v.X;\r
748             mat[5] = v.Y;\r
749             mat[10] = v.Z;\r
750             mat[15] = 1;\r
751 \r
752             return mat;\r
753         }\r
754 \r
755         public static float[] Lerp(float[] matrix1, float[] matrix2, float amount)\r
756         {\r
757 \r
758             float[] lerp = new float[16];\r
759             //Probably not doing this as a loop is cheaper(unrolling)\r
760             //also for performance we probably should not create new objects\r
761             // but meh.\r
762             for (int x = 0; x < 16; x++)\r
763             {\r
764                 lerp[x] = matrix1[x] + ((matrix2[x] - matrix1[x]) * amount);\r
765             }\r
766 \r
767             return lerp;\r
768         }\r
769 \r
770 \r
771         public static bool GluProject(OpenTK.Vector3 objPos, OpenTK.Matrix4 modelMatrix, OpenTK.Matrix4 projMatrix, int[] viewport, out OpenTK.Vector3 screenPos)\r
772         {\r
773             OpenTK.Vector4 _in;\r
774             OpenTK.Vector4 _out;\r
775 \r
776             _in.X = objPos.X;\r
777             _in.Y = objPos.Y;\r
778             _in.Z = objPos.Z;\r
779             _in.W = 1.0f;\r
780 \r
781             _out = OpenTK.Vector4.Transform(_in, modelMatrix);\r
782             _in = OpenTK.Vector4.Transform(_out, projMatrix);\r
783 \r
784             if (_in.W <= 0.0)\r
785             {\r
786                 screenPos = OpenTK.Vector3.Zero;\r
787                 return false;\r
788             }\r
789 \r
790             _in.X /= _in.W;\r
791             _in.Y /= _in.W;\r
792             _in.Z /= _in.W;\r
793             /* Map x, y and z to range 0-1 */\r
794             _in.X = _in.X * 0.5f + 0.5f;\r
795             _in.Y = _in.Y * 0.5f + 0.5f;\r
796             _in.Z = _in.Z * 0.5f + 0.5f;\r
797 \r
798             /* Map x,y to viewport */\r
799             _in.X = _in.X * viewport[2] + viewport[0];\r
800             _in.Y = _in.Y * viewport[3] + viewport[1];\r
801 \r
802             screenPos.X = _in.X;\r
803             screenPos.Y = _in.Y;\r
804             screenPos.Z = _in.Z;\r
805 \r
806             return true;\r
807         }\r
808     }\r
809 \r
810     public class attachment_point\r
811     {\r
812         public string name;\r
813         public string joint;\r
814         public Vector3 position;\r
815         public Quaternion rotation;\r
816         public int id;\r
817         public int group;\r
818 \r
819         public GLMesh jointmesh;\r
820         public int jointmeshindex;\r
821 \r
822         public attachment_point(XmlNode node)\r
823         {\r
824             name = node.Attributes.GetNamedItem("name").Value;\r
825             joint = node.Attributes.GetNamedItem("joint").Value;\r
826             position = VisualParamEx.XmlParseVector(node.Attributes.GetNamedItem("position").Value);\r
827             rotation = VisualParamEx.XmlParseRotation(node.Attributes.GetNamedItem("rotation").Value);\r
828             id = Int32.Parse(node.Attributes.GetNamedItem("id").Value);\r
829             group = Int32.Parse(node.Attributes.GetNamedItem("group").Value);\r
830         }\r
831 \r
832     }\r
833 \r
834     /// <summary>\r
835     /// Subclass of LindenMesh that adds vertex, index, and texture coordinate\r
836     /// arrays suitable for pushing direct to OpenGL\r
837     /// </summary>\r
838     public class GLMesh : LindenMesh\r
839     {\r
840         /// <summary>\r
841         /// Subclass of LODMesh that adds an index array suitable for pushing\r
842         /// direct to OpenGL\r
843         /// </summary>\r
844         /// \r
845 \r
846         public int teFaceID;\r
847         public Dictionary<int, VisualParamEx> _evp = new Dictionary<int, VisualParamEx>();\r
848 \r
849         new public class LODMesh : LindenMesh.LODMesh\r
850         {\r
851             public ushort[] Indices;\r
852 \r
853             public override void LoadMesh(string filename)\r
854             {\r
855                 base.LoadMesh(filename);\r
856 \r
857                 // Generate the index array\r
858                 Indices = new ushort[_numFaces * 3];\r
859                 int current = 0;\r
860                 for (int i = 0; i < _numFaces; i++)\r
861                 {\r
862                     Indices[current++] = (ushort)_faces[i].Indices[0];\r
863                     Indices[current++] = (ushort)_faces[i].Indices[1];\r
864                     Indices[current++] = (ushort)_faces[i].Indices[2];\r
865                 }\r
866             }\r
867         }\r
868 \r
869         /// <summary>\r
870         /// \r
871         /// </summary>\r
872         public struct GLData\r
873         {\r
874             public float[] Vertices;\r
875             public float[] Normals;\r
876             public ushort[] Indices;\r
877             public float[] TexCoords;\r
878             public Vector3 Center;\r
879             public float[] weights; //strictly these are constant and don't need instancing with the GLMesh\r
880             public string[] skinJoints;  //strictly these are constant and don't need instancing with the GLMesh\r
881         }\r
882 \r
883         public static GLData baseRenderData;\r
884         public GLData RenderData;\r
885         public GLData OrigRenderData;\r
886         public GLData MorphRenderData;\r
887 \r
888         public GLAvatar av;\r
889 \r
890         public GLMesh(string name)\r
891             : base(name)\r
892         {\r
893         }\r
894 \r
895         public GLMesh(GLMesh source,GLAvatar av)\r
896             :base(source.Name)\r
897         {\r
898             this.av = av;\r
899             // Make a new GLMesh copy from the supplied source\r
900     \r
901             RenderData.Vertices = new float[source.RenderData.Vertices.Length];\r
902             RenderData.Normals = new float[source.RenderData.Normals.Length];\r
903             RenderData.TexCoords = new float[source.RenderData.TexCoords.Length];\r
904             RenderData.Indices = new ushort[source.RenderData.Indices.Length];\r
905 \r
906             RenderData.weights = new float[source.RenderData.weights.Length];\r
907             RenderData.skinJoints = new string[source.RenderData.skinJoints.Length];\r
908 \r
909             Array.Copy(source.RenderData.Vertices,RenderData.Vertices,source.RenderData.Vertices.Length);\r
910             Array.Copy(source.RenderData.Normals, RenderData.Normals, source.RenderData.Normals.Length);\r
911 \r
912             Array.Copy(source.RenderData.TexCoords, RenderData.TexCoords, source.RenderData.TexCoords.Length);\r
913             Array.Copy(source.RenderData.Indices, RenderData.Indices, source.RenderData.Indices.Length);\r
914             Array.Copy(source.RenderData.weights, RenderData.weights, source.RenderData.weights.Length);\r
915             Array.Copy(source.RenderData.skinJoints, RenderData.skinJoints, source.RenderData.skinJoints.Length);\r
916 \r
917 \r
918             RenderData.Center = new Vector3(source.RenderData.Center);\r
919 \r
920             teFaceID = source.teFaceID;\r
921 \r
922             _rotationAngles = new Vector3(source.RotationAngles);\r
923             _scale = new Vector3(source.Scale);\r
924             _position = new Vector3(source.Position);\r
925 \r
926             // We should not need to instance these the reference from the top should be constant\r
927             _evp = source._evp;\r
928             _morphs = source._morphs;\r
929 \r
930             OrigRenderData.Indices = new ushort[source.RenderData.Indices.Length];\r
931             OrigRenderData.TexCoords = new float[source.RenderData.TexCoords.Length];\r
932             OrigRenderData.Vertices = new float[source.RenderData.Vertices.Length];\r
933 \r
934             MorphRenderData.Vertices = new float[source.RenderData.Vertices.Length];\r
935 \r
936             Array.Copy(source.RenderData.Vertices, OrigRenderData.Vertices, source.RenderData.Vertices.Length);\r
937             Array.Copy(source.RenderData.Vertices, MorphRenderData.Vertices, source.RenderData.Vertices.Length);\r
938 \r
939             Array.Copy(source.RenderData.TexCoords, OrigRenderData.TexCoords, source.RenderData.TexCoords.Length);\r
940             Array.Copy(source.RenderData.Indices, OrigRenderData.Indices, source.RenderData.Indices.Length);\r
941 \r
942 \r
943 \r
944         }\r
945 \r
946         public void setMeshPos(Vector3 pos)\r
947         {\r
948             _position = pos;\r
949         }\r
950 \r
951         public void setMeshRot(Vector3 rot)\r
952         {\r
953             _rotationAngles = rot;\r
954         }\r
955 \r
956         public override void LoadMesh(string filename)\r
957         {\r
958             base.LoadMesh(filename);\r
959 \r
960             float minX, minY, minZ;\r
961             minX = minY = minZ = Single.MaxValue;\r
962             float maxX, maxY, maxZ;\r
963             maxX = maxY = maxZ = Single.MinValue;\r
964 \r
965             // Generate the vertex array\r
966             RenderData.Vertices = new float[_numVertices * 3];\r
967             RenderData.Normals = new float[_numVertices * 3];\r
968 \r
969              Quaternion quat = Quaternion.CreateFromEulers(0, 0, (float)(Math.PI/4.0));\r
970 \r
971             int current = 0;\r
972             for (int i = 0; i < _numVertices; i++)\r
973             {\r
974 \r
975                     RenderData.Normals[current] = _vertices[i].Normal.X;\r
976                     RenderData.Vertices[current++] = _vertices[i].Coord.X;\r
977                     RenderData.Normals[current] = _vertices[i].Normal.Y;\r
978                     RenderData.Vertices[current++] = _vertices[i].Coord.Y;\r
979                     RenderData.Normals[current] = _vertices[i].Normal.Z;\r
980                     RenderData.Vertices[current++] = _vertices[i].Coord.Z;\r
981       \r
982                 if (_vertices[i].Coord.X < minX)\r
983                     minX = _vertices[i].Coord.X;\r
984                 else if (_vertices[i].Coord.X > maxX)\r
985                     maxX = _vertices[i].Coord.X;\r
986 \r
987                 if (_vertices[i].Coord.Y < minY)\r
988                     minY = _vertices[i].Coord.Y;\r
989                 else if (_vertices[i].Coord.Y > maxY)\r
990                     maxY = _vertices[i].Coord.Y;\r
991 \r
992                 if (_vertices[i].Coord.Z < minZ)\r
993                     minZ = _vertices[i].Coord.Z;\r
994                 else if (_vertices[i].Coord.Z > maxZ)\r
995                     maxZ = _vertices[i].Coord.Z;\r
996             }\r
997 \r
998             // Calculate the center-point from the bounding box edges\r
999             RenderData.Center = new Vector3((minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2);\r
1000 \r
1001             // Generate the index array\r
1002             RenderData.Indices = new ushort[_numFaces * 3];\r
1003             current = 0;\r
1004             for (int i = 0; i < _numFaces; i++)\r
1005             {\r
1006                 RenderData.Indices[current++] = (ushort)_faces[i].Indices[0];\r
1007                 RenderData.Indices[current++] = (ushort)_faces[i].Indices[1];\r
1008                 RenderData.Indices[current++] = (ushort)_faces[i].Indices[2];\r
1009             }\r
1010 \r
1011             // Generate the texcoord array\r
1012             RenderData.TexCoords = new float[_numVertices * 2];\r
1013             current = 0;\r
1014             for (int i = 0; i < _numVertices; i++)\r
1015             {\r
1016                     RenderData.TexCoords[current++] = _vertices[i].TexCoord.X;\r
1017                     RenderData.TexCoords[current++] = _vertices[i].TexCoord.Y;\r
1018             }\r
1019 \r
1020             RenderData.weights = new float[_numVertices];\r
1021             for (int i = 0; i < _numVertices; i++)\r
1022             {\r
1023                 RenderData.weights[i] = _vertices[i].Weight;\r
1024             }\r
1025 \r
1026             RenderData.skinJoints = new string[_skinJoints.Length+3];\r
1027             for (int i = 1; i < _skinJoints.Length; i++)\r
1028             {\r
1029                 RenderData.skinJoints[i] = _skinJoints[i];\r
1030             }\r
1031 \r
1032 \r
1033         }\r
1034 \r
1035         public override void LoadLODMesh(int level, string filename)\r
1036         {\r
1037             LODMesh lod = new LODMesh();\r
1038             lod.LoadMesh(filename);\r
1039             _lodMeshes[level] = lod;\r
1040         }\r
1041 \r
1042         public void applyjointweights()\r
1043         {\r
1044     \r
1045             /*Each weight actually contains two pieces of information. \r
1046              * The number to the left of the decimal point is the index of the joint and also \r
1047              * implicitly indexes to the following joint. The actual weight is to the right of \r
1048              * the decimal point and interpolates between these two joints. The index is into an \r
1049              * "expanded" list of joints, not just a linear array of the joints as defined in the \r
1050              * skeleton file. In particular, any joint that has more than one child will be repeated \r
1051              * in the list for each of its children.\r
1052              */\r
1053 \r
1054             float weight=-9999;\r
1055             int jointindex=0;\r
1056             float factor;\r
1057 \r
1058             Bone ba = null;\r
1059             Bone bb = null;\r
1060 \r
1061             for (int v = 0, x=0; v < RenderData.Vertices.Length; v=v+3, x++)\r
1062             {\r
1063                 if (weight != RenderData.weights[x])\r
1064                 {\r
1065 \r
1066                     jointindex = (int)Math.Floor(weight = RenderData.weights[x]);\r
1067                     factor = RenderData.weights[x] - jointindex;\r
1068                     weight = weight - jointindex;\r
1069 \r
1070                     string jointname="", jointname2="";\r
1071 \r
1072                     if (this.Name == "upperBodyMesh")\r
1073                     {\r
1074                         jointname = skeleton.mUpperMeshMapping[jointindex];\r
1075                         jointindex++;\r
1076                         jointname2 = skeleton.mUpperMeshMapping[jointindex];\r
1077                     }\r
1078                     else if (Name == "lowerBodyMesh")\r
1079                     {\r
1080                         jointname = skeleton.mLowerMeshMapping[jointindex];\r
1081                         jointindex++;\r
1082                         jointname2 = skeleton.mLowerMeshMapping[jointindex];\r
1083                     }\r
1084                     else if (Name == "headMesh")\r
1085                     {\r
1086                         jointname = skeleton.mHeadMeshMapping[jointindex];\r
1087                         jointindex++;\r
1088                         jointname2 = skeleton.mHeadMeshMapping[jointindex];\r
1089                     }\r
1090                     else\r
1091                     {\r
1092                         return; // not interested in this mesh\r
1093                     }\r
1094                     \r
1095                     \r
1096                     if (jointname == "")\r
1097                     {\r
1098                         //Don't yet handle this, its a split joint to two children\r
1099                         continue;\r
1100                     }\r
1101                     else\r
1102                     {\r
1103                         ba = av.skel.mBones[jointname];\r
1104                     }\r
1105 \r
1106                     if(jointname2=="")\r
1107                     {\r
1108                         bb=null;\r
1109                     }\r
1110                     else\r
1111                     {\r
1112                         bb = av.skel.mBones[jointname2];  \r
1113                     }\r
1114                 }\r
1115 \r
1116                 //Special cases 0 is not used\r
1117                 // ON upper torso 5 and 10 are not used\r
1118                 // 4 is neck and 6 and 11 are the left and right collar bones\r
1119 \r
1120                 Vector3 lerp;\r
1121 \r
1122                 Vector3 offset;\r
1123                 Quaternion rot = ba.getRotation();\r
1124 \r
1125                 if (bb != null)\r
1126                 {\r
1127                     Vector3 oa = ba.getOffset() - ba.getOrigOffset();\r
1128                     Vector3 ob = bb.getOffset() - bb.getOrigOffset();\r
1129                     lerp = Vector3.Lerp(oa, ob, weight);\r
1130                     offset = Vector3.Lerp(ba.getOffset(), bb.getOffset(), weight);\r
1131                 }\r
1132                 else\r
1133                 {\r
1134                     lerp = ba.getOffset()- ba.getOrigOffset();\r
1135                     offset = ba.getOffset();\r
1136                     rot = ba.getRotation();\r
1137                 }\r
1138 \r
1139                 Vector3 pos = new Vector3(MorphRenderData.Vertices[v], MorphRenderData.Vertices[v + 1], MorphRenderData.Vertices[v + 2]);\r
1140                 pos = pos + lerp; \r
1141                 pos = pos - offset;\r
1142                 pos = pos * rot;\r
1143                 pos = pos + offset;\r
1144                \r
1145                 RenderData.Vertices[v] = pos.X;\r
1146                 RenderData.Vertices[v + 1] = pos.Y;\r
1147                 RenderData.Vertices[v + 2] = pos.Z;\r
1148             }\r
1149         }\r
1150 \r
1151         public void morphmesh(Morph morph, float weight)\r
1152         {\r
1153             for (int v = 0; v < morph.NumVertices; v++)\r
1154             {\r
1155                 MorphVertex mvx = morph.Vertices[v];\r
1156 \r
1157                 uint i = mvx.VertexIndex;\r
1158 \r
1159                 MorphRenderData.Vertices[i * 3] = OrigRenderData.Vertices[i*3] + mvx.Coord.X * weight;\r
1160                 MorphRenderData.Vertices[(i * 3) + 1] = OrigRenderData.Vertices[i * 3 + 1] + mvx.Coord.Y * weight;\r
1161                 MorphRenderData.Vertices[(i * 3) + 2] = OrigRenderData.Vertices[i * 3 + 2] + mvx.Coord.Z * weight;\r
1162 \r
1163                 RenderData.TexCoords[i * 2] = OrigRenderData.TexCoords[i * 2] + mvx.TexCoord.X * weight;\r
1164                 RenderData.TexCoords[(i * 2) + 1] = OrigRenderData.TexCoords[i * 2 + 1] + mvx.TexCoord.Y * weight;\r
1165  \r
1166             }\r
1167         }\r
1168     }\r
1169 \r
1170     public class GLAvatar\r
1171     {\r
1172         private static Dictionary<string, GLMesh> _defaultmeshes = new Dictionary<string, GLMesh>();\r
1173         public Dictionary<string, GLMesh> _meshes = new Dictionary<string, GLMesh>();\r
1174 \r
1175         public skeleton skel = new skeleton(); \r
1176         public static Dictionary<int, attachment_point> attachment_points = new Dictionary<int, attachment_point>();\r
1177 \r
1178         public bool _wireframe = true;\r
1179         public bool _showSkirt = false;\r
1180 \r
1181         public VisualParamEx.EparamSex msex;\r
1182 \r
1183         public byte[] VisualAppearanceParameters = new byte[1024];\r
1184         bool vpsent = false;\r
1185         static bool lindenMeshesLoaded = false;\r
1186 \r
1187         public GLAvatar()\r
1188         {\r
1189             foreach (KeyValuePair<string,GLMesh> kvp in _defaultmeshes)\r
1190             {\r
1191                 GLMesh mesh = new GLMesh(kvp.Value,this); // Instance our meshes\r
1192                 _meshes.Add(kvp.Key, mesh);\r
1193                 \r
1194             }\r
1195         }\r
1196 \r
1197         public static void dumptweaks()\r
1198         {\r
1199 \r
1200             for(int x=0;x<VisualParamEx.tweakable_params.Count;x++)\r
1201             {\r
1202                 VisualParamEx vpe = (VisualParamEx)VisualParamEx.tweakable_params.GetByIndex(x);\r
1203                 Console.WriteLine(string.Format("{0} is {1}",x,vpe.Name));\r
1204             }\r
1205 \r
1206 \r
1207         }\r
1208 \r
1209         public static void loadlindenmeshes2(string LODfilename)\r
1210         {\r
1211             // Already have mashes loaded?\r
1212             if (lindenMeshesLoaded) return;\r
1213 \r
1214             attachment_points.Clear();\r
1215 \r
1216 \r
1217             string basedir = Directory.GetCurrentDirectory() + System.IO.Path.DirectorySeparatorChar + "character" + System.IO.Path.DirectorySeparatorChar;\r
1218 \r
1219             XmlDocument lad = new XmlDocument();\r
1220             lad.Load(basedir + LODfilename);\r
1221 \r
1222             //Firstly read the skeleton section this contains attachment point info and the bone deform info for visual params\r
1223             // And load the skeleton file in to the bones class\r
1224 \r
1225             XmlNodeList skeleton = lad.GetElementsByTagName("skeleton");\r
1226             string skeletonfilename = skeleton[0].Attributes.GetNamedItem("file_name").Value;\r
1227             Bone.loadbones(skeletonfilename);\r
1228 \r
1229             // Next read all the skeleton child nodes, we have attachment points and bone deform params\r
1230             // attachment points are an offset and rotation from a bone location\r
1231             // the name of the bone they reference is the joint paramater\r
1232             // params in the skeleton nodes are bone deforms, eg leg length changes the scale of the leg bones\r
1233 \r
1234             foreach (XmlNode skeletonnode in skeleton[0].ChildNodes)\r
1235             {\r
1236                 if (skeletonnode.Name == "attachment_point")\r
1237                 {\r
1238                     attachment_point point = new attachment_point(skeletonnode);\r
1239                     attachment_points.Add(point.id, point);\r
1240                 }\r
1241 \r
1242                 if (skeletonnode.Name == "param")\r
1243                 {\r
1244                     //Bone deform param\r
1245                     VisualParamEx vp = new VisualParamEx(skeletonnode, VisualParamEx.ParamType.TYPE_BONEDEFORM);\r
1246                 }\r
1247             }\r
1248 \r
1249             //Now we parse the mesh nodes, mesh nodes reference a particular LLM file with a LOD\r
1250             //and also list VisualParams for the various mesh morphs that can be applied\r
1251 \r
1252             XmlNodeList meshes = lad.GetElementsByTagName("mesh");\r
1253             foreach (XmlNode meshNode in meshes)\r
1254             {\r
1255                 string type = meshNode.Attributes.GetNamedItem("type").Value;\r
1256                 int lod = Int32.Parse(meshNode.Attributes.GetNamedItem("lod").Value);\r
1257                 string fileName = meshNode.Attributes.GetNamedItem("file_name").Value;\r
1258 \r
1259                 GLMesh mesh = (_defaultmeshes.ContainsKey(type) ? _defaultmeshes[type] : new GLMesh(type));\r
1260 \r
1261                 if (meshNode.HasChildNodes)\r
1262                 {\r
1263                     foreach (XmlNode paramnode in meshNode.ChildNodes)\r
1264                     {\r
1265                         if (paramnode.Name == "param")\r
1266                         {\r
1267                             VisualParamEx vp = new VisualParamEx(paramnode, VisualParamEx.ParamType.TYPE_MORPH);\r
1268 \r
1269                             mesh._evp.Add(vp.ParamID, vp); //Not sure we really need this may optimise out later\r
1270                             vp.morphmesh = mesh.Name;\r
1271                         }\r
1272                     }\r
1273                 }\r
1274 \r
1275                 // Set up the texture elemenets for each mesh\r
1276                 // And hack the eyeball position\r
1277                 switch (mesh.Name)\r
1278                 {\r
1279                     case "lowerBodyMesh":\r
1280                         mesh.teFaceID = (int)AvatarTextureIndex.LowerBaked;\r
1281                         break;\r
1282 \r
1283                     case "upperBodyMesh":\r
1284                         mesh.teFaceID = (int)AvatarTextureIndex.UpperBaked;\r
1285                         break;\r
1286 \r
1287                     case "headMesh":\r
1288                         mesh.teFaceID = (int)AvatarTextureIndex.HeadBaked;\r
1289                         break;\r
1290 \r
1291                     case "hairMesh":\r
1292                         mesh.teFaceID = (int)AvatarTextureIndex.HairBaked;\r
1293                         break;\r
1294 \r
1295                     case "eyelashMesh":\r
1296                         mesh.teFaceID = (int)AvatarTextureIndex.HeadBaked;\r
1297                         break;\r
1298 \r
1299                     case "eyeBallRightMesh":\r
1300                         mesh.setMeshPos(Bone.mBones["mEyeLeft"].getOffset());\r
1301                         //mesh.setMeshRot(Bone.getRotation("mEyeLeft"));\r
1302                         mesh.teFaceID = (int)AvatarTextureIndex.EyesBaked;\r
1303                         break;\r
1304 \r
1305                     case "eyeBallLeftMesh":\r
1306                         mesh.setMeshPos(Bone.mBones["mEyeRight"].getOffset());\r
1307                         //mesh.setMeshRot(Bone.getRotation("mEyeRight"));\r
1308                         mesh.teFaceID = (int)AvatarTextureIndex.EyesBaked;\r
1309                         break;\r
1310 \r
1311                     case "skirtMesh":\r
1312                         mesh.teFaceID = (int)AvatarTextureIndex.SkirtBaked;\r
1313                         break;\r
1314 \r
1315                     default:\r
1316                         mesh.teFaceID = 0;\r
1317                         break;\r
1318                 }\r
1319 \r
1320                 if (lod == 0)\r
1321                     mesh.LoadMesh(basedir + fileName);\r
1322                 else\r
1323                     mesh.LoadLODMesh(lod, basedir + fileName);\r
1324 \r
1325                 _defaultmeshes[type] = mesh;\r
1326 \r
1327             }\r
1328 \r
1329             // Next are the textureing params, skipping for the moment\r
1330 \r
1331             XmlNodeList colors = lad.GetElementsByTagName("global_color");\r
1332             {\r
1333                 foreach (XmlNode globalcolornode in colors)\r
1334                 {\r
1335                     foreach (XmlNode node in globalcolornode.ChildNodes)\r
1336                     {\r
1337                         if (node.Name == "param")\r
1338                         {\r
1339                             VisualParamEx vp = new VisualParamEx(node, VisualParamEx.ParamType.TYPE_COLOR);\r
1340                         }\r
1341                     }\r
1342                 }\r
1343             }\r
1344 \r
1345             // Get layer paramaters, a bit of a verbose way to do it but we probably want to get access\r
1346             // to some of the other data not just the <param> tag\r
1347 \r
1348             XmlNodeList layer_sets = lad.GetElementsByTagName("layer_set");\r
1349             {\r
1350                 foreach (XmlNode layer_set in layer_sets)\r
1351                 {\r
1352                     foreach (XmlNode layer in layer_set.ChildNodes)\r
1353                     {\r
1354                         foreach (XmlNode layernode in layer.ChildNodes)\r
1355                         {\r
1356                             if (layernode.Name == "param")\r
1357                             {\r
1358                                 VisualParamEx vp = new VisualParamEx(layernode, VisualParamEx.ParamType.TYPE_COLOR);\r
1359                             }\r
1360                         }\r
1361                     }\r
1362                 }\r
1363             }\r
1364 \r
1365             // Next are the driver parameters, these are parameters that change multiple real parameters\r
1366 \r
1367             XmlNodeList drivers = lad.GetElementsByTagName("driver_parameters");\r
1368 \r
1369             foreach (XmlNode node in drivers[0].ChildNodes) //lazy \r
1370             {\r
1371                 if (node.Name == "param")\r
1372                 {\r
1373                     VisualParamEx vp = new VisualParamEx(node, VisualParamEx.ParamType.TYPE_DRIVER);\r
1374                 }\r
1375             }\r
1376 \r
1377             lindenMeshesLoaded = true;\r
1378         }\r
1379 \r
1380         public void morphtest(Avatar av, int param, float weight)\r
1381         {\r
1382             VisualParamEx vpx;\r
1383             if (VisualParamEx.allParams.TryGetValue(param,out vpx))\r
1384             {\r
1385 \r
1386                 Logger.Log(string.Format("Applying visual parameter {0} id {1} value {2}", vpx.Name, vpx.ParamID, weight), Helpers.LogLevel.Info); \r
1387 \r
1388                 //weight = weight * 2.0f;\r
1389                 //weight=weight-1.0f;\r
1390 \r
1391                 float value = vpx.MinValue + ((vpx.MaxValue - vpx.MinValue) * weight);\r
1392 \r
1393                \r
1394                 if (vpx.pType == VisualParamEx.ParamType.TYPE_MORPH)\r
1395                 {\r
1396                     // Its a morph\r
1397                     GLMesh mesh;\r
1398                     if (_meshes.TryGetValue(vpx.morphmesh, out mesh))\r
1399                     {\r
1400                         foreach (LindenMesh.Morph morph in mesh.Morphs) //optimise me to a dictionary\r
1401                         {\r
1402                             if (morph.Name == vpx.Name)\r
1403                             {\r
1404                                 mesh.morphmesh(morph, value);\r
1405                             }\r
1406                         }\r
1407                     }\r
1408                     else\r
1409                     {\r
1410                         // Not a mesh morph \r
1411 \r
1412                         // Its a volume deform, these appear to be related to collision volumes\r
1413                         /*\r
1414                         if (vpx.VolumeDeforms == null)\r
1415                         {\r
1416                             Logger.Log(String.Format("paramater {0} has invalid mesh {1}", param, vpx.morphmesh), Helpers.LogLevel.Warning);\r
1417                         }\r
1418                         else\r
1419                         {\r
1420                             foreach (KeyValuePair<string, VisualParamEx.VolumeDeform> kvp in vpx.VolumeDeforms)\r
1421                             {\r
1422                                 skel.deformbone(kvp.Key, kvp.Value.pos, kvp.Value.scale);\r
1423                             }\r
1424                         }\r
1425                          * */\r
1426 \r
1427                      }\r
1428                   \r
1429                 }\r
1430                 else\r
1431                 {\r
1432                     // Its not a morph, it might be a driver though\r
1433                     if (vpx.pType == VisualParamEx.ParamType.TYPE_DRIVER)\r
1434                     {\r
1435                         foreach (VisualParamEx.driven child in vpx.childparams)\r
1436                         {\r
1437                             morphtest(av, child.id, weight); //TO DO use minmax if they are present\r
1438                         }\r
1439                         return;\r
1440                     }\r
1441 \r
1442                     //Is this a bone deform?\r
1443                     if (vpx.pType == VisualParamEx.ParamType.TYPE_BONEDEFORM)\r
1444                     {\r
1445                         foreach (KeyValuePair<string, Vector3> kvp in vpx.BoneDeforms)\r
1446                         {\r
1447                             skel.deformbone(kvp.Key, new Vector3(0,0,0),kvp.Value*value,Quaternion.Identity);\r
1448                         }\r
1449                     }\r
1450                     else\r
1451                     {\r
1452                         Logger.Log(String.Format("paramater {0} is not a morph and not a driver", param), Helpers.LogLevel.Warning);\r
1453                     }\r
1454                 }\r
1455 \r
1456             }\r
1457             else\r
1458             {\r
1459                 Logger.Log("Invalid paramater " + param.ToString(), Helpers.LogLevel.Warning);\r
1460             }\r
1461 \r
1462             /*\r
1463             foreach (GLMesh mesh in _meshes.Values)\r
1464             {\r
1465                 VisualParamEx evp;\r
1466                 if (mesh._evp.TryGetValue(param, out evp))\r
1467                 {\r
1468                     foreach (LindenMesh.Morph morph in mesh.Morphs)\r
1469                     {\r
1470                         if (morph.Name == evp.Name)\r
1471                         {\r
1472                             mesh.morphmesh(morph, weight);\r
1473                         }\r
1474                     }\r
1475                 }\r
1476                 else\r
1477                 {\r
1478                     Console.WriteLine("No such visual param in morphs");\r
1479                 }\r
1480             \r
1481             }\r
1482              */\r
1483         }\r
1484 \r
1485         public void morph(Avatar av)\r
1486         {\r
1487 \r
1488             if (av.VisualParameters == null)\r
1489                 return;\r
1490 \r
1491 \r
1492             ThreadPool.QueueUserWorkItem(sync =>\r
1493             {\r
1494                 int x = 0;\r
1495 \r
1496                 if (av.VisualParameters.Length > 123)\r
1497                 {\r
1498                     if (av.VisualParameters[31] > 0.5)\r
1499                     {\r
1500                         msex = VisualParamEx.EparamSex.SEX_MALE;\r
1501                     }\r
1502                     else\r
1503                     {\r
1504                         msex = VisualParamEx.EparamSex.SEX_FEMALE;\r
1505                     }\r
1506                 }\r
1507                  \r
1508 \r
1509                 foreach (byte vpvalue in av.VisualParameters)\r
1510                 {\r
1511                     if (vpsent==true && VisualAppearanceParameters[x] == vpvalue)\r
1512                     {\r
1513                         x++;\r
1514                         continue;\r
1515                     }\r
1516 \r
1517                     VisualAppearanceParameters[x] = vpvalue;\r
1518 \r
1519                     if (x >= VisualParamEx.tweakable_params.Count)\r
1520                     {\r
1521                         Logger.Log("Two many visual paramaters in Avatar appearance", Helpers.LogLevel.Warning);\r
1522                         break;\r
1523                     }\r
1524 \r
1525                     VisualParamEx vpe = (VisualParamEx)VisualParamEx.tweakable_params.GetByIndex(x);\r
1526 \r
1527                     if (vpe.sex != VisualParamEx.EparamSex.SEX_BOTH && vpe.sex != msex)\r
1528                     {\r
1529                         x++;\r
1530                         continue;\r
1531                     }\r
1532 \r
1533                     float value = (vpvalue / 255.0f);\r
1534                     this.morphtest(av, vpe.ParamID, value);\r
1535                     \r
1536                     x++;\r
1537                 }\r
1538 \r
1539                 vpsent = true;\r
1540 \r
1541                 foreach (GLMesh mesh in _meshes.Values)\r
1542                 {\r
1543                     mesh.applyjointweights();\r
1544                 }\r
1545             });\r
1546         }\r
1547     }\r
1548 \r
1549     public class RenderAvatar : SceneObject\r
1550     {\r
1551         public RenderAvatar()\r
1552         {\r
1553             Type = SceneObjectType.Avatar;\r
1554         }\r
1555 \r
1556         public override Primitive BasePrim\r
1557         {\r
1558             get { return avatar; }\r
1559             set { if (value is Avatar) avatar = (Avatar)value; }\r
1560         }\r
1561 \r
1562         public GLAvatar glavatar = new GLAvatar();\r
1563         public Avatar avatar;\r
1564         public FaceData[] data = new FaceData[32];\r
1565         public Dictionary<UUID, Animation> animlist = new Dictionary<UUID, Animation>();\r
1566         public Dictionary<WearableType, AppearanceManager.WearableData> Wearables = new Dictionary<WearableType, AppearanceManager.WearableData>();\r
1567 \r
1568     }\r
1569 \r
1570     public class skeleton\r
1571     {\r
1572         public Dictionary<string, Bone> mBones;\r
1573         public static Dictionary<int, string> mUpperMeshMapping = new Dictionary<int, string>();\r
1574         public static Dictionary<int, string> mLowerMeshMapping = new Dictionary<int, string>();\r
1575         public static Dictionary<int, string> mHeadMeshMapping = new Dictionary<int, string>();\r
1576 \r
1577 \r
1578 \r
1579         public skeleton()\r
1580         {\r
1581             mBones = new Dictionary<string, Bone>(Bone.mBones); //copy from the static defines\r
1582 \r
1583             //FUDGE\r
1584             if (mUpperMeshMapping.Count == 0)\r
1585             {\r
1586                 mUpperMeshMapping.Add(1, "mPelvis");\r
1587                 mUpperMeshMapping.Add(2, "mTorso");\r
1588                 mUpperMeshMapping.Add(3, "mChest");\r
1589                 mUpperMeshMapping.Add(4, "mNeck");\r
1590                 mUpperMeshMapping.Add(5, "");\r
1591                 mUpperMeshMapping.Add(6, "mCollarLeft");\r
1592                 mUpperMeshMapping.Add(7, "mShoulderLeft");\r
1593                 mUpperMeshMapping.Add(8, "mElbowLeft");\r
1594                 mUpperMeshMapping.Add(9, "mWristLeft");\r
1595                 mUpperMeshMapping.Add(10, "");\r
1596                 mUpperMeshMapping.Add(11, "mCollarRight");\r
1597                 mUpperMeshMapping.Add(12, "mShoulderRight");\r
1598                 mUpperMeshMapping.Add(13, "mElbowRight");\r
1599                 mUpperMeshMapping.Add(14, "mWristRight");\r
1600                 mUpperMeshMapping.Add(15, "");\r
1601 \r
1602                 mLowerMeshMapping.Add(1,"mPelvis");\r
1603                 mLowerMeshMapping.Add(2, "mHipRight");\r
1604                 mLowerMeshMapping.Add(3, "mKneeRight");\r
1605                 mLowerMeshMapping.Add(4, "mAnkleRight");\r
1606                 mLowerMeshMapping.Add(5, "");\r
1607                 mLowerMeshMapping.Add(6, "mHipLeft");\r
1608                 mLowerMeshMapping.Add(7, "mKneeLeft");\r
1609                 mLowerMeshMapping.Add(8, "mAnkleLeft");\r
1610                 mLowerMeshMapping.Add(9, "");\r
1611 \r
1612                 mHeadMeshMapping.Add(1, "mNeck");\r
1613                 mHeadMeshMapping.Add(2, "mHead");\r
1614                 mHeadMeshMapping.Add(3, "");\r
1615 \r
1616             }\r
1617         }\r
1618 \r
1619         public void deformbone(string name, Vector3 pos, Vector3 scale, Quaternion rotation)\r
1620         {\r
1621             Bone bone;\r
1622             if (mBones.TryGetValue(name, out bone))\r
1623             {\r
1624                 bone.deformbone(pos, scale, rotation);\r
1625             }\r
1626         }\r
1627 \r
1628         //TODO check offset and rot calcuations should each offset be multiplied by its parent rotation in\r
1629         // a standard child/parent rot/offset way?\r
1630         public Vector3 getOffset(string bonename)\r
1631         {\r
1632             Bone b;\r
1633             if (mBones.TryGetValue(bonename, out b))\r
1634             {\r
1635                 return (b.getOffset());\r
1636             }\r
1637             else\r
1638             {\r
1639                 return Vector3.Zero;\r
1640             }\r
1641         }\r
1642 \r
1643         public Quaternion getRotation(string bonename)\r
1644         {\r
1645             Bone b;\r
1646             if (mBones.TryGetValue(bonename, out b))\r
1647             {\r
1648                 return (b.getRotation());\r
1649             }\r
1650             else\r
1651             {\r
1652                 return Quaternion.Identity;\r
1653             }\r
1654         }\r
1655     }\r
1656 \r
1657     public class Bone\r
1658     {\r
1659         public string name;\r
1660         public Vector3 pos;\r
1661         public Quaternion rot;\r
1662         public Vector3 scale;\r
1663         public Vector3 piviot;\r
1664 \r
1665         public Vector3 orig_pos;\r
1666         public Quaternion orig_rot;\r
1667         public Vector3 orig_scale;\r
1668         public Vector3 orig_piviot;\r
1669 \r
1670         Matrix4 mDeformMatrix=Matrix4.Identity;\r
1671 \r
1672         public Bone parent;\r
1673 \r
1674         public List<Bone> children = new List<Bone>();\r
1675 \r
1676         public static Dictionary<string, Bone> mBones = new Dictionary<string, Bone>();\r
1677         public static Dictionary<int, Bone> mIndexedBones = new Dictionary<int, Bone>();\r
1678         static int boneaddindex = 0;\r
1679 \r
1680         public Bone()\r
1681         {\r
1682         }\r
1683 \r
1684         public Bone(Bone source)\r
1685         {\r
1686             name = String.Copy(source.name);\r
1687             pos = new Vector3(source.pos);\r
1688             rot = new Quaternion(source.rot);\r
1689             scale = new Vector3(source.scale);\r
1690             piviot = new Vector3(source.piviot);\r
1691 \r
1692             orig_piviot = source.orig_piviot;\r
1693             orig_pos = source.orig_pos;\r
1694             orig_rot = source.orig_rot;\r
1695             orig_scale = source.orig_scale;\r
1696 \r
1697             mDeformMatrix = new Matrix4(source.mDeformMatrix);\r
1698         }\r
1699 \r
1700         public static void loadbones(string skeletonfilename)\r
1701         {\r
1702             mBones.Clear();\r
1703             string basedir = Directory.GetCurrentDirectory() + System.IO.Path.DirectorySeparatorChar + "character" + System.IO.Path.DirectorySeparatorChar;\r
1704             XmlDocument skeleton = new XmlDocument();\r
1705             skeleton.Load(basedir + skeletonfilename);\r
1706             XmlNode boneslist = skeleton.GetElementsByTagName("linden_skeleton")[0];\r
1707             addbone(boneslist.ChildNodes[0], null);\r
1708         }\r
1709 \r
1710         public static void addbone(XmlNode bone, Bone parent)\r
1711         {\r
1712 \r
1713             if (bone.Name != "bone")\r
1714                 return;\r
1715 \r
1716             Bone b = new Bone();\r
1717             b.name = bone.Attributes.GetNamedItem("name").Value;\r
1718 \r
1719             string pos = bone.Attributes.GetNamedItem("pos").Value;\r
1720             string[] posparts = pos.Split(' ');\r
1721             b.pos = new Vector3(float.Parse(posparts[0]), float.Parse(posparts[1]), float.Parse(posparts[2]));\r
1722             b.orig_pos = new Vector3(b.pos);\r
1723 \r
1724             string rot = bone.Attributes.GetNamedItem("rot").Value;\r
1725             string[] rotparts = rot.Split(' ');\r
1726             b.rot = 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));\r
1727             b.orig_rot = new Quaternion(b.rot);\r
1728 \r
1729             string scale = bone.Attributes.GetNamedItem("scale").Value;\r
1730             string[] scaleparts = scale.Split(' ');\r
1731             b.scale = new Vector3(float.Parse(scaleparts[0]), float.Parse(scaleparts[1]), float.Parse(scaleparts[2]));\r
1732             b.orig_scale = new Vector3(b.scale);\r
1733 \r
1734 \r
1735             float[] deform = Math3D.CreateSRTMatrix(new Vector3(1,1,1), b.rot, b.orig_pos);\r
1736             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]);\r
1737 \r
1738             //TODO piviot\r
1739 \r
1740             b.parent = parent;\r
1741 \r
1742             if (parent != null)\r
1743                 parent.children.Add(b);\r
1744 \r
1745             mBones.Add(b.name, b);\r
1746             mIndexedBones.Add(boneaddindex++, b);\r
1747 \r
1748             Logger.Log("Found bone " + b.name, Helpers.LogLevel.Info);\r
1749 \r
1750             foreach (XmlNode childbone in bone.ChildNodes)\r
1751             {\r
1752                 addbone(childbone, b);\r
1753             }\r
1754 \r
1755         }\r
1756 \r
1757         public void deformbone(Vector3 pos, Vector3 scale, Quaternion rot)\r
1758         {\r
1759             float[] deform = Math3D.CreateSRTMatrix(scale, rot, this.orig_pos);\r
1760             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]);\r
1761             this.pos = Bone.mBones[name].orig_pos + pos;\r
1762             this.scale = Bone.mBones[name].orig_scale + scale;\r
1763             this.rot = Bone.mBones[name].orig_rot * rot;\r
1764         }\r
1765 \r
1766         public Matrix4 getdeform()\r
1767         {\r
1768             if (this.parent != null)\r
1769             {\r
1770                 return mDeformMatrix * parent.getdeform();\r
1771             }\r
1772             else\r
1773             {\r
1774                 return mDeformMatrix;\r
1775             }\r
1776         }\r
1777 \r
1778         public Vector3 getOffset()\r
1779         {\r
1780             if (parent != null)\r
1781             {\r
1782                 Quaternion totalrot = getParentRot(); // we don't want this joints rotation included\r
1783                 Vector3 parento = parent.getOffset();\r
1784                 Vector3 mepre = pos * scale;\r
1785                 mepre = mepre * totalrot;\r
1786                 return parento+ mepre;\r
1787             }\r
1788             else\r
1789             {\r
1790                 return (pos * scale) *getRotation();\r
1791             }\r
1792         }\r
1793 \r
1794         public Vector3 getMyOffset()\r
1795         {\r
1796             return pos * scale;\r
1797         }\r
1798 \r
1799         public Vector3 getOrigOffset()\r
1800         {\r
1801             if (parent != null)\r
1802             {\r
1803                 return ((parent.getOrigOffset()) + orig_pos);\r
1804             }\r
1805             else\r
1806             {\r
1807                 return orig_pos;\r
1808             }\r
1809         }\r
1810 \r
1811         public static Quaternion getRotation(string bonename)\r
1812         {\r
1813             Bone b;\r
1814             if (mBones.TryGetValue(bonename, out b))\r
1815             {\r
1816                 return (b.getRotation());\r
1817             }\r
1818             else\r
1819             {\r
1820                 return Quaternion.Identity;\r
1821             }\r
1822         }\r
1823 \r
1824 \r
1825         public Quaternion getParentRot()\r
1826         {\r
1827             Quaternion totalrot = Quaternion.Identity;\r
1828 \r
1829             if (parent != null)\r
1830             {\r
1831                 totalrot = parent.getRotation();\r
1832             }\r
1833 \r
1834             return totalrot;\r
1835 \r
1836         }\r
1837 \r
1838         public Quaternion getRotation()\r
1839         {\r
1840             Quaternion totalrot = rot;\r
1841 \r
1842             if (parent != null)\r
1843             {\r
1844                 totalrot = rot* parent.getRotation();\r
1845             }\r
1846 \r
1847             return totalrot;\r
1848         }\r
1849 \r
1850     }\r
1851 \r
1852     public class VisualParamEx\r
1853     {\r
1854 \r
1855         static public Dictionary<int,VisualParamEx> allParams = new  Dictionary<int,VisualParamEx>();\r
1856         static public Dictionary<int, VisualParamEx> deformParams = new Dictionary<int, VisualParamEx>();\r
1857         static public Dictionary<int, VisualParamEx> morphParams = new Dictionary<int, VisualParamEx>();\r
1858         static public Dictionary<int, VisualParamEx> drivenParams = new Dictionary<int, VisualParamEx>();\r
1859         static public SortedList tweakable_params = new SortedList();\r
1860 \r
1861         public Dictionary<string, Vector3> BoneDeforms = null;\r
1862         public Dictionary<string, VolumeDeform> VolumeDeforms = null;\r
1863         public List<driven> childparams = null;\r
1864 \r
1865         public string morphmesh = null;\r
1866 \r
1867         enum GroupType\r
1868         {\r
1869             VISUAL_PARAM_GROUP_TWEAKABLE = 0,\r
1870             VISUAL_PARAM_GROUP_ANIMATABLE,\r
1871             VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT,\r
1872         }\r
1873 \r
1874         public struct VolumeDeform\r
1875         {\r
1876             public string name;\r
1877             public Vector3 scale;\r
1878             public Vector3 pos;\r
1879         }\r
1880 \r
1881         public enum EparamSex\r
1882         {\r
1883             SEX_BOTH = 0,\r
1884             SEX_FEMALE = 1,\r
1885             SEX_MALE = 2\r
1886         }\r
1887 \r
1888         public enum ParamType\r
1889         {\r
1890             TYPE_BONEDEFORM,\r
1891             TYPE_MORPH,\r
1892             TYPE_DRIVER,\r
1893             TYPE_COLOR,\r
1894             TYPE_LAYER\r
1895         }\r
1896 \r
1897         public struct driven\r
1898         {\r
1899             public int id;\r
1900             public float max1;\r
1901             public float max2;\r
1902             public float min1;\r
1903             public float min2;\r
1904             public bool hasMinMax;\r
1905         }\r
1906 \r
1907         public string meshname;\r
1908         \r
1909         /// <summary>Index of this visual param</summary>\r
1910         public int ParamID;\r
1911         /// <summary>Internal name</summary>\r
1912         public string Name;\r
1913         /// <summary>Group ID this parameter belongs to</summary>\r
1914         public int Group;\r
1915         /// <summary>Name of the wearable this parameter belongs to</summary>\r
1916         public string Wearable;\r
1917         /// <summary>Displayable label of this characteristic</summary>\r
1918         public string Label;\r
1919         /// <summary>Displayable label for the minimum value of this characteristic</summary>\r
1920         public string LabelMin;\r
1921         /// <summary>Displayable label for the maximum value of this characteristic</summary>\r
1922         public string LabelMax;\r
1923         /// <summary>Default value</summary>\r
1924         public float DefaultValue;\r
1925         /// <summary>Minimum value</summary>\r
1926         public float MinValue;\r
1927         /// <summary>Maximum value</summary>\r
1928         public float MaxValue;\r
1929         /// <summary>Is this param used for creation of bump layer?</summary>\r
1930         public bool IsBumpAttribute;\r
1931         /// <summary>Alpha blending/bump info</summary>\r
1932         public VisualAlphaParam? AlphaParams;\r
1933         /// <summary>Color information</summary>\r
1934         public VisualColorParam? ColorParams;\r
1935         /// <summary>Array of param IDs that are drivers for this parameter</summary>\r
1936         public int[] Drivers;\r
1937         /// <summary>The Avatar Sex that this parameter applies to</summary>\r
1938         public EparamSex sex;\r
1939 \r
1940         public ParamType pType;\r
1941 \r
1942         public static int count = 0;\r
1943 \r
1944         /// <summary>\r
1945         /// Set all the values through the constructor\r
1946         /// </summary>\r
1947         /// <param name="paramID">Index of this visual param</param>\r
1948         /// <param name="name">Internal name</param>\r
1949         /// <param name="group"></param>\r
1950         /// <param name="wearable"></param>\r
1951         /// <param name="label">Displayable label of this characteristic</param>\r
1952         /// <param name="labelMin">Displayable label for the minimum value of this characteristic</param>\r
1953         /// <param name="labelMax">Displayable label for the maximum value of this characteristic</param>\r
1954         /// <param name="def">Default value</param>\r
1955         /// <param name="min">Minimum value</param>\r
1956         /// <param name="max">Maximum value</param>\r
1957         /// <param name="isBumpAttribute">Is this param used for creation of bump layer?</param>\r
1958         /// <param name="drivers">Array of param IDs that are drivers for this parameter</param>\r
1959         /// <param name="alpha">Alpha blending/bump info</param>\r
1960         /// <param name="colorParams">Color information</param>\r
1961         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)\r
1962         {\r
1963             ParamID = paramID;\r
1964             Name = name;\r
1965             Group = group;\r
1966             Wearable = wearable;\r
1967             Label = label;\r
1968             LabelMin = labelMin;\r
1969             LabelMax = labelMax;\r
1970             DefaultValue = def;\r
1971             MaxValue = max;\r
1972             MinValue = min;\r
1973             IsBumpAttribute = isBumpAttribute;\r
1974             Drivers = drivers;\r
1975             AlphaParams = alpha;\r
1976             ColorParams = colorParams;\r
1977             sex = EparamSex.SEX_BOTH;\r
1978         }\r
1979 \r
1980         public VisualParamEx(XmlNode node, ParamType pt)\r
1981         {\r
1982             pType = pt;\r
1983    \r
1984             ParamID = Int32.Parse(node.Attributes.GetNamedItem("id").Value);\r
1985             Name = node.Attributes.GetNamedItem("name").Value;\r
1986             Group = Int32.Parse(node.Attributes.GetNamedItem("group").Value);\r
1987 \r
1988             //These dont exist for facal expresion morphs\r
1989             if(node.Attributes.GetNamedItem("wearable")!=null)\r
1990                 Wearable = node.Attributes.GetNamedItem("wearable").Value;\r
1991             \r
1992             MinValue = float.Parse(node.Attributes.GetNamedItem("value_min").Value);\r
1993             MaxValue = float.Parse(node.Attributes.GetNamedItem("value_max").Value);\r
1994 \r
1995             // These do not exists for driven parameters\r
1996             if (node.Attributes.GetNamedItem("label_min") != null)\r
1997             {\r
1998                 LabelMin = node.Attributes.GetNamedItem("label_min").Value;\r
1999             }\r
2000 \r
2001             if (node.Attributes.GetNamedItem("label_max") != null)\r
2002             {\r
2003                 LabelMax = node.Attributes.GetNamedItem("label_max").Value;\r
2004             }\r
2005 \r
2006             XmlNode sexnode = node.Attributes.GetNamedItem("sex");\r
2007 \r
2008             if (sexnode != null)\r
2009             {\r
2010                 if (sexnode.Value == "male")\r
2011                 {\r
2012                     sex = EparamSex.SEX_MALE;\r
2013                 }\r
2014                 else\r
2015                 {\r
2016                     sex = EparamSex.SEX_FEMALE;\r
2017                 }\r
2018 \r
2019             }\r
2020 \r
2021             Group = int.Parse(node.Attributes.GetNamedItem("group").Value);\r
2022 \r
2023             if (Group == (int)GroupType.VISUAL_PARAM_GROUP_TWEAKABLE)\r
2024             {\r
2025                 if(!tweakable_params.ContainsKey(ParamID)) //stupid duplicate shared params\r
2026                 {\r
2027                     tweakable_params.Add(this.ParamID, this);\r
2028                 }\r
2029                 Logger.Log(String.Format("Adding tweakable paramater ID {0} {1}", count, this.Name),Helpers.LogLevel.Info);\r
2030                 count++;\r
2031             }\r
2032 \r
2033             //TODO other paramaters but these arew concerned with editing the GUI display so not too fussed at the moment\r
2034 \r
2035             try\r
2036             {\r
2037                 allParams.Add(ParamID, this);\r
2038             }\r
2039             catch (Exception e)\r
2040             {\r
2041                 Logger.Log("Duplicate VisualParam in allParams id " + ParamID.ToString(), Helpers.LogLevel.Info);\r
2042             }\r
2043 \r
2044             if (pt == ParamType.TYPE_BONEDEFORM)\r
2045             {\r
2046                 // If we are in the skeleton section then we also have bone deforms to parse\r
2047                 BoneDeforms = new Dictionary<string, Vector3>();\r
2048                 if(node.HasChildNodes && node.ChildNodes[0].HasChildNodes)\r
2049                 {\r
2050                     ParseBoneDeforms(node.ChildNodes[0].ChildNodes); \r
2051                 }\r
2052                 deformParams.Add(ParamID,this);\r
2053             }\r
2054 \r
2055             if (pt == ParamType.TYPE_MORPH)\r
2056             {\r
2057                 VolumeDeforms = new Dictionary<string, VolumeDeform>();\r
2058                 if (node.HasChildNodes && node.ChildNodes[0].HasChildNodes)\r
2059                 {\r
2060                     ParseVolumeDeforms(node.ChildNodes[0].ChildNodes);\r
2061                 }\r
2062 \r
2063                 try\r
2064                 {\r
2065                     morphParams.Add(ParamID, this);\r
2066                 }\r
2067                 catch (Exception e)\r
2068                 {\r
2069                     Logger.Log("Duplicate VisualParam in morphParams id " + ParamID.ToString(), Helpers.LogLevel.Info);\r
2070                 }\r
2071 \r
2072             }\r
2073 \r
2074             if (pt == ParamType.TYPE_DRIVER)\r
2075             {\r
2076                 childparams = new List<driven>();\r
2077                 if (node.HasChildNodes && node.ChildNodes[0].HasChildNodes) //LAZY\r
2078                 {\r
2079                     ParseDrivers(node.ChildNodes[0].ChildNodes);\r
2080                 }\r
2081 \r
2082                 drivenParams.Add(ParamID, this);\r
2083 \r
2084             }\r
2085 \r
2086             if (pt == ParamType.TYPE_COLOR)\r
2087             {\r
2088                 if (node.HasChildNodes)\r
2089                 {\r
2090                     foreach (XmlNode colorchild in node.ChildNodes)\r
2091                     {\r
2092                         if (colorchild.Name == "param_color")\r
2093                         {\r
2094                             //TODO extract <value color="50, 25, 5, 255" />\r
2095                         }\r
2096                     }\r
2097 \r
2098                 }\r
2099             }\r
2100         \r
2101         }\r
2102 \r
2103         void ParseBoneDeforms(XmlNodeList deforms)\r
2104         {\r
2105             foreach (XmlNode node in deforms)\r
2106             {\r
2107                 if (node.Name == "bone")\r
2108                 {\r
2109                     string name = node.Attributes.GetNamedItem("name").Value;\r
2110                     Vector3 scale = XmlParseVector(node.Attributes.GetNamedItem("scale").Value);\r
2111                     BoneDeforms.Add(name, scale);\r
2112                 }\r
2113             }\r
2114         }\r
2115 \r
2116         void ParseVolumeDeforms(XmlNodeList deforms)\r
2117         {\r
2118             foreach (XmlNode node in deforms)\r
2119             {\r
2120                 if (node.Name == "volume_morph")\r
2121                 {\r
2122                     VolumeDeform vd = new VolumeDeform();\r
2123                     vd.name = node.Attributes.GetNamedItem("name").Value;\r
2124                     vd.name = vd.name.ToLower();\r
2125 \r
2126                     if (node.Attributes.GetNamedItem("scale") != null)\r
2127                     {\r
2128                         vd.scale = XmlParseVector(node.Attributes.GetNamedItem("scale").Value);\r
2129                     }\r
2130                     else\r
2131                     {\r
2132                         vd.scale = new Vector3(0, 0, 0);\r
2133                     }\r
2134 \r
2135                     if (node.Attributes.GetNamedItem("pos") != null)\r
2136                     {\r
2137                         vd.pos = XmlParseVector(node.Attributes.GetNamedItem("pos").Value);\r
2138                     }\r
2139                     else\r
2140                     {\r
2141                         vd.pos = new Vector3(0f, 0f, 0f);\r
2142                     }\r
2143 \r
2144                     VolumeDeforms.Add(vd.name, vd);\r
2145                 }\r
2146             }\r
2147         }\r
2148 \r
2149         void ParseDrivers(XmlNodeList drivennodes)\r
2150         {\r
2151             foreach (XmlNode node in drivennodes)\r
2152             {\r
2153                 if (node.Name == "driven")\r
2154                 {\r
2155                     driven d = new driven();\r
2156 \r
2157                     d.id = Int32.Parse(node.Attributes.GetNamedItem("id").Value);\r
2158                     XmlNode param = node.Attributes.GetNamedItem("max1");\r
2159                     if (param != null)\r
2160                     {\r
2161                         d.max1 = float.Parse(param.Value);\r
2162                         d.max2 = float.Parse(node.Attributes.GetNamedItem("max2").Value);\r
2163                         d.min1 = float.Parse(node.Attributes.GetNamedItem("min1").Value);\r
2164                         d.max2 = float.Parse(node.Attributes.GetNamedItem("min2").Value);\r
2165                         d.hasMinMax = true;\r
2166                     }\r
2167                     else\r
2168                     {\r
2169                         d.hasMinMax = false;\r
2170                     }\r
2171 \r
2172                     childparams.Add(d);    \r
2173                                    \r
2174                 }\r
2175             }\r
2176         }\r
2177 \r
2178         public static Vector3 XmlParseVector(string data)\r
2179         {\r
2180             string[] posparts = data.Split(' ');\r
2181             return new Vector3(float.Parse(posparts[0]), float.Parse(posparts[1]), float.Parse(posparts[2]));\r
2182         }\r
2183 \r
2184         public static Quaternion XmlParseRotation(string data)\r
2185         {\r
2186             string[] rotparts = data.Split(' ');\r
2187             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));\r
2188         }\r
2189     }\r
2190 }\r