OSDN Git Service

* Implemented texture animations
[radegast/radegast.git] / Radegast / GUI / Rendering / RenderingHelpers.cs
1 using System;\r
2 using System.Collections.Generic;\r
3 using System.Linq;\r
4 using System.Text;\r
5 using System.IO;\r
6 using System.Xml;\r
7 using OpenTK.Graphics.OpenGL;\r
8 using System.Runtime.InteropServices;\r
9 using OpenMetaverse;\r
10 using OpenMetaverse.Rendering;\r
11 \r
12 namespace Radegast.Rendering\r
13 {\r
14     public class FaceData\r
15     {\r
16         public float[] Vertices;\r
17         public ushort[] Indices;\r
18         public float[] TexCoords;\r
19         public float[] Normals;\r
20         public int PickingID = -1;\r
21         public int VertexVBO = -1;\r
22         public int IndexVBO = -1;\r
23         public TextureInfo TextureInfo = new TextureInfo();\r
24         public BoundingSphere BoundingSphere = new BoundingSphere();\r
25         public static int VertexSize = 32; // sizeof (vertex), 2  x vector3 + 1 x vector2 = 8 floats x 4 bytes = 32 bytes \r
26         public TextureAnimationInfo AnimInfo;\r
27 \r
28         public void CheckVBO(Face face)\r
29         {\r
30             if (VertexVBO == -1)\r
31             {\r
32                 Vertex[] vArray = face.Vertices.ToArray();\r
33                 GL.GenBuffers(1, out VertexVBO);\r
34                 GL.BindBuffer(BufferTarget.ArrayBuffer, VertexVBO);\r
35                 GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vArray.Length * VertexSize), vArray, BufferUsageHint.StreamDraw);\r
36             }\r
37 \r
38             if (IndexVBO == -1)\r
39             {\r
40                 ushort[] iArray = face.Indices.ToArray();\r
41                 GL.GenBuffers(1, out IndexVBO);\r
42                 GL.BindBuffer(BufferTarget.ElementArrayBuffer, IndexVBO);\r
43                 GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(iArray.Length * sizeof(ushort)), iArray, BufferUsageHint.StreamDraw);\r
44             }\r
45         }\r
46     }\r
47 \r
48     public class TextureAnimationInfo\r
49     {\r
50         public Primitive.TextureAnimation PrimAnimInfo;\r
51         public float CurrentFrame;\r
52         public double CurrentTime;\r
53         public bool PingPong;\r
54         float LastTime = 0f;\r
55         float TotalTime = 0f;\r
56 \r
57         public void Step(double lastFrameTime)\r
58         {\r
59             float numFrames = 1f;\r
60             float fullLength = 1f;\r
61 \r
62             if (PrimAnimInfo.Length > 0)\r
63             {\r
64                 numFrames = PrimAnimInfo.Length;\r
65             }\r
66             else\r
67             {\r
68                 numFrames = Math.Max(1f, (float)(PrimAnimInfo.SizeX * PrimAnimInfo.SizeY));\r
69             }\r
70 \r
71             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.PING_PONG) != 0)\r
72             {\r
73                 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)\r
74                 {\r
75                     fullLength = 2f * numFrames;\r
76                 }\r
77                 else if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.LOOP) != 0)\r
78                 {\r
79                     fullLength = 2f * numFrames - 2f;\r
80                     fullLength = Math.Max(1f, fullLength);\r
81                 }\r
82                 else\r
83                 {\r
84                     fullLength = 2f * numFrames - 1f;\r
85                     fullLength = Math.Max(1f, fullLength);\r
86                 }\r
87             }\r
88             else\r
89             {\r
90                 fullLength = numFrames;\r
91             }\r
92 \r
93             float frameCounter;\r
94             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)\r
95             {\r
96                 frameCounter = (float)lastFrameTime * PrimAnimInfo.Rate + LastTime;\r
97             }\r
98             else\r
99             {\r
100                 TotalTime += (float)lastFrameTime;\r
101                 frameCounter = TotalTime * PrimAnimInfo.Rate;\r
102             }\r
103             LastTime = frameCounter;\r
104 \r
105             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.LOOP) != 0)\r
106             {\r
107                 frameCounter %= fullLength;\r
108             }\r
109             else\r
110             {\r
111                 frameCounter = Math.Min(fullLength - 1f, frameCounter);\r
112             }\r
113 \r
114             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) == 0)\r
115             {\r
116                 frameCounter = (float)Math.Floor(frameCounter + 0.01f);\r
117             }\r
118 \r
119             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.PING_PONG) != 0)\r
120             {\r
121                 if (frameCounter > numFrames)\r
122                 {\r
123                     if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)\r
124                     {\r
125                         frameCounter = numFrames - (frameCounter - numFrames);\r
126                     }\r
127                     else\r
128                     {\r
129                         frameCounter = (numFrames - 1.99f) - (frameCounter - numFrames);\r
130                     }\r
131                 }\r
132             }\r
133 \r
134             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.REVERSE) != 0)\r
135             {\r
136                 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)\r
137                 {\r
138                     frameCounter = numFrames - frameCounter;\r
139                 }\r
140                 else\r
141                 {\r
142                     frameCounter = (numFrames - 0.99f) - frameCounter;\r
143                 }\r
144             }\r
145 \r
146             frameCounter += PrimAnimInfo.Start;\r
147 \r
148             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) == 0)\r
149             {\r
150                 frameCounter = (float)Math.Round(frameCounter);\r
151             }\r
152 \r
153 \r
154             GL.MatrixMode(MatrixMode.Texture);\r
155             GL.LoadIdentity();\r
156 \r
157             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.ROTATE) != 0)\r
158             {\r
159                 GL.Translate(0.5f, 0.5f, 0f);\r
160                 GL.Rotate(Utils.RAD_TO_DEG * frameCounter, OpenTK.Vector3d.UnitZ);\r
161                 GL.Translate(-0.5f, -0.5f, 0f);\r
162             }\r
163             else if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SCALE) != 0)\r
164             {\r
165                 GL.Scale(frameCounter, frameCounter, 0);\r
166             }\r
167             else // Translate\r
168             {\r
169                 float sizeX = Math.Max(1f, (float)PrimAnimInfo.SizeX);\r
170                 float sizeY = Math.Max(1f, (float)PrimAnimInfo.SizeY);\r
171 \r
172                 GL.Scale(1f / sizeX, 1f / sizeY, 0);\r
173                 GL.Translate(frameCounter % sizeX, Math.Floor(frameCounter / sizeY), 0);\r
174             }\r
175 \r
176             GL.MatrixMode(MatrixMode.Modelview);\r
177         }\r
178 \r
179         [Obsolete("Use Step() instead")]\r
180         public void ExperimentalStep(double time)\r
181         {\r
182             int reverseFactor = 1;\r
183             float rate = PrimAnimInfo.Rate;\r
184 \r
185             if (rate < 0)\r
186             {\r
187                 rate = -rate;\r
188                 reverseFactor = -reverseFactor;\r
189             }\r
190 \r
191             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.REVERSE) != 0)\r
192             {\r
193                 reverseFactor = -reverseFactor;\r
194             }\r
195 \r
196             CurrentTime += time;\r
197             double totalTime = 1 / rate;\r
198 \r
199             uint x = Math.Max(1, PrimAnimInfo.SizeX);\r
200             uint y = Math.Max(1, PrimAnimInfo.SizeY);\r
201             uint nrFrames = x * y;\r
202 \r
203             if (PrimAnimInfo.Length > 0 && PrimAnimInfo.Length < nrFrames)\r
204             {\r
205                 nrFrames = (uint)PrimAnimInfo.Length;\r
206             }\r
207 \r
208             GL.MatrixMode(MatrixMode.Texture);\r
209             GL.LoadIdentity();\r
210 \r
211             if (CurrentTime >= totalTime)\r
212             {\r
213                 CurrentTime = 0;\r
214                 CurrentFrame++;\r
215                 if (CurrentFrame > nrFrames) CurrentFrame = (uint)PrimAnimInfo.Start;\r
216                 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.PING_PONG) != 0)\r
217                 {\r
218                     PingPong = !PingPong;\r
219                 }\r
220             }\r
221 \r
222             float smoothOffset = 0f;\r
223 \r
224             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)\r
225             {\r
226                 smoothOffset = (float)(CurrentTime / totalTime) * reverseFactor;\r
227             }\r
228 \r
229             float f = CurrentFrame;\r
230             if (reverseFactor < 0)\r
231             {\r
232                 f = nrFrames - CurrentFrame;\r
233             }\r
234 \r
235             if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.ROTATE) == 0) // not rotaating\r
236             {\r
237                 GL.Scale(1f / x, 1f / y, 0f);\r
238                 GL.Translate((f % x) + smoothOffset, f / y, 0);\r
239             }\r
240             else\r
241             {\r
242                 smoothOffset = (float)(CurrentTime * PrimAnimInfo.Rate);\r
243                 double startAngle = PrimAnimInfo.Start;\r
244                 double endAngle = PrimAnimInfo.Length;\r
245                 double angle = startAngle + (endAngle - startAngle) * smoothOffset;\r
246                 GL.Translate(0.5f, 0.5f, 0f);\r
247                 GL.Rotate(Utils.RAD_TO_DEG * angle, OpenTK.Vector3d.UnitZ);\r
248                 GL.Translate(-0.5f, -0.5f, 0f);\r
249             }\r
250 \r
251             GL.MatrixMode(MatrixMode.Modelview);\r
252         }\r
253 \r
254     }\r
255 \r
256 \r
257     public class TextureInfo\r
258     {\r
259         public System.Drawing.Image Texture;\r
260         public int TexturePointer;\r
261         public bool HasAlpha;\r
262         public UUID TextureID;\r
263     }\r
264 \r
265     public class TextureLoadItem\r
266     {\r
267         public FaceData Data;\r
268         public Primitive Prim;\r
269         public Primitive.TextureEntryFace TeFace;\r
270     }\r
271 \r
272     public enum RenderPass\r
273     {\r
274         Picking,\r
275         Simple,\r
276         Alpha\r
277     }\r
278 \r
279     public static class Render\r
280     {\r
281         public static IRendering Plugin;\r
282     }\r
283 \r
284     public static class RHelp\r
285     {\r
286         public static OpenTK.Vector2 TKVector3(Vector2 v)\r
287         {\r
288             return new OpenTK.Vector2(v.X, v.Y);\r
289         }\r
290 \r
291         public static OpenTK.Vector3 TKVector3(Vector3 v)\r
292         {\r
293             return new OpenTK.Vector3(v.X, v.Y, v.Z);\r
294         }\r
295 \r
296         public static OpenTK.Vector4 TKVector3(Vector4 v)\r
297         {\r
298             return new OpenTK.Vector4(v.X, v.Y, v.Z, v.W);\r
299         }\r
300     }\r
301 \r
302     /// <summary>\r
303     /// Represents camera object\r
304     /// </summary>\r
305     public class Camera\r
306     {\r
307         Vector3 mPosition;\r
308         Vector3 mFocalPoint;\r
309         bool mModified;\r
310 \r
311         /// <summary>Camera position</summary>\r
312         public Vector3 Position { get { return mPosition; } set { mPosition = value; Modify(); } }\r
313         /// <summary>Camera target</summary>\r
314         public Vector3 FocalPoint { get { return mFocalPoint; } set { mFocalPoint = value; Modify(); } }\r
315         /// <summary>Zoom level</summary>\r
316         public float Zoom;\r
317         /// <summary>Draw distance</summary>\r
318         public float Far;\r
319         /// <summary>Has camera been modified</summary>\r
320         public bool Modified { get { return mModified; } set { mModified = value; } }\r
321 \r
322         public double TimeToTarget = 0d;\r
323 \r
324         public Vector3 RenderPosition;\r
325         public Vector3 RenderFocalPoint;\r
326 \r
327         void Modify()\r
328         {\r
329             mModified = true;\r
330             if (TimeToTarget <= 0)\r
331             {\r
332                 RenderPosition = Position;\r
333                 RenderFocalPoint = FocalPoint;\r
334             }\r
335         }\r
336 \r
337         public void Step(double time)\r
338         {\r
339             TimeToTarget -= time;\r
340             if (TimeToTarget <= time)\r
341             {\r
342                 EndMove();\r
343                 return;\r
344             }\r
345 \r
346             mModified = true;\r
347 \r
348             float pctElapsed = (float)(time / TimeToTarget);\r
349 \r
350             if (RenderPosition != Position)\r
351             {\r
352                 float distance = Vector3.Distance(RenderPosition, Position);\r
353                 RenderPosition = Vector3.Lerp(RenderPosition, Position, (float)(distance * pctElapsed));\r
354             }\r
355 \r
356             if (RenderFocalPoint != FocalPoint)\r
357             {\r
358                 RenderFocalPoint = Interpolate(RenderFocalPoint, FocalPoint, pctElapsed);\r
359             }\r
360         }\r
361 \r
362         Vector3 Interpolate(Vector3 start, Vector3 end, float fraction)\r
363         {\r
364             float distance = Vector3.Distance(start, end);\r
365             Vector3 direction = end - start;\r
366             return start + direction * fraction;\r
367         }\r
368 \r
369         public void EndMove()\r
370         {\r
371             mModified = true;\r
372             TimeToTarget = 0;\r
373             RenderPosition = Position;\r
374             RenderFocalPoint = FocalPoint;\r
375         }\r
376     }\r
377 \r
378     public static class MeshToOBJ\r
379     {\r
380         public static bool MeshesToOBJ(Dictionary<uint, FacetedMesh> meshes, string filename)\r
381         {\r
382             StringBuilder obj = new StringBuilder();\r
383             StringBuilder mtl = new StringBuilder();\r
384 \r
385             FileInfo objFileInfo = new FileInfo(filename);\r
386 \r
387             string mtlFilename = objFileInfo.FullName.Substring(objFileInfo.DirectoryName.Length + 1,\r
388                 objFileInfo.FullName.Length - (objFileInfo.DirectoryName.Length + 1) - 4) + ".mtl";\r
389 \r
390             obj.AppendLine("# Created by libprimrender");\r
391             obj.AppendLine("mtllib ./" + mtlFilename);\r
392             obj.AppendLine();\r
393 \r
394             mtl.AppendLine("# Created by libprimrender");\r
395             mtl.AppendLine();\r
396 \r
397             int primNr = 0;\r
398             foreach (FacetedMesh mesh in meshes.Values)\r
399             {\r
400                 for (int j = 0; j < mesh.Faces.Count; j++)\r
401                 {\r
402                     Face face = mesh.Faces[j];\r
403 \r
404                     if (face.Vertices.Count > 2)\r
405                     {\r
406                         string mtlName = String.Format("material{0}-{1}", primNr, face.ID);\r
407                         Primitive.TextureEntryFace tex = face.TextureFace;\r
408                         string texName = tex.TextureID.ToString() + ".tga";\r
409 \r
410                         // FIXME: Convert the source to TGA (if needed) and copy to the destination\r
411 \r
412                         float shiny = 0.00f;\r
413                         switch (tex.Shiny)\r
414                         {\r
415                             case Shininess.High:\r
416                                 shiny = 1.00f;\r
417                                 break;\r
418                             case Shininess.Medium:\r
419                                 shiny = 0.66f;\r
420                                 break;\r
421                             case Shininess.Low:\r
422                                 shiny = 0.33f;\r
423                                 break;\r
424                         }\r
425 \r
426                         obj.AppendFormat("g face{0}-{1}{2}", primNr, face.ID, Environment.NewLine);\r
427 \r
428                         mtl.AppendLine("newmtl " + mtlName);\r
429                         mtl.AppendFormat("Ka {0} {1} {2}{3}", tex.RGBA.R, tex.RGBA.G, tex.RGBA.B, Environment.NewLine);\r
430                         mtl.AppendFormat("Kd {0} {1} {2}{3}", tex.RGBA.R, tex.RGBA.G, tex.RGBA.B, Environment.NewLine);\r
431                         //mtl.AppendFormat("Ks {0} {1} {2}{3}");\r
432                         mtl.AppendLine("Tr " + tex.RGBA.A);\r
433                         mtl.AppendLine("Ns " + shiny);\r
434                         mtl.AppendLine("illum 1");\r
435                         if (tex.TextureID != UUID.Zero && tex.TextureID != Primitive.TextureEntry.WHITE_TEXTURE)\r
436                             mtl.AppendLine("map_Kd ./" + texName);\r
437                         mtl.AppendLine();\r
438 \r
439                         // Write the vertices, texture coordinates, and vertex normals for this side\r
440                         for (int k = 0; k < face.Vertices.Count; k++)\r
441                         {\r
442                             Vertex vertex = face.Vertices[k];\r
443 \r
444                             #region Vertex\r
445 \r
446                             Vector3 pos = vertex.Position;\r
447 \r
448                             // Apply scaling\r
449                             pos *= mesh.Prim.Scale;\r
450 \r
451                             // Apply rotation\r
452                             pos *= mesh.Prim.Rotation;\r
453 \r
454                             // The root prim position is sim-relative, while child prim positions are\r
455                             // parent-relative. We want to apply parent-relative translations but not\r
456                             // sim-relative ones\r
457                             if (mesh.Prim.ParentID != 0)\r
458                                 pos += mesh.Prim.Position;\r
459 \r
460                             obj.AppendFormat("v {0} {1} {2}{3}", pos.X, pos.Y, pos.Z, Environment.NewLine);\r
461 \r
462                             #endregion Vertex\r
463 \r
464                             #region Texture Coord\r
465 \r
466                             obj.AppendFormat("vt {0} {1}{2}", vertex.TexCoord.X, vertex.TexCoord.Y,\r
467                                 Environment.NewLine);\r
468 \r
469                             #endregion Texture Coord\r
470 \r
471                             #region Vertex Normal\r
472 \r
473                             // HACK: Sometimes normals are getting set to <NaN,NaN,NaN>\r
474                             if (!Single.IsNaN(vertex.Normal.X) && !Single.IsNaN(vertex.Normal.Y) && !Single.IsNaN(vertex.Normal.Z))\r
475                                 obj.AppendFormat("vn {0} {1} {2}{3}", vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z,\r
476                                     Environment.NewLine);\r
477                             else\r
478                                 obj.AppendLine("vn 0.0 1.0 0.0");\r
479 \r
480                             #endregion Vertex Normal\r
481                         }\r
482 \r
483                         obj.AppendFormat("# {0} vertices{1}", face.Vertices.Count, Environment.NewLine);\r
484                         obj.AppendLine();\r
485                         obj.AppendLine("usemtl " + mtlName);\r
486 \r
487                         #region Elements\r
488 \r
489                         // Write all of the faces (triangles) for this side\r
490                         for (int k = 0; k < face.Indices.Count / 3; k++)\r
491                         {\r
492                             obj.AppendFormat("f -{0}/-{0}/-{0} -{1}/-{1}/-{1} -{2}/-{2}/-{2}{3}",\r
493                                 face.Vertices.Count - face.Indices[k * 3 + 0],\r
494                                 face.Vertices.Count - face.Indices[k * 3 + 1],\r
495                                 face.Vertices.Count - face.Indices[k * 3 + 2],\r
496                                 Environment.NewLine);\r
497                         }\r
498 \r
499                         obj.AppendFormat("# {0} elements{1}", face.Indices.Count / 3, Environment.NewLine);\r
500                         obj.AppendLine();\r
501 \r
502                         #endregion Elements\r
503                     }\r
504                 }\r
505                 primNr++;\r
506             }\r
507 \r
508             try\r
509             {\r
510                 File.WriteAllText(filename, obj.ToString());\r
511                 File.WriteAllText(mtlFilename, mtl.ToString());\r
512             }\r
513             catch (Exception)\r
514             {\r
515                 return false;\r
516             }\r
517 \r
518             return true;\r
519         }\r
520     }\r
521 \r
522     public static class Math3D\r
523     {\r
524         // Column-major:\r
525         // |  0  4  8 12 |\r
526         // |  1  5  9 13 |\r
527         // |  2  6 10 14 |\r
528         // |  3  7 11 15 |\r
529 \r
530         public static float[] CreateTranslationMatrix(Vector3 v)\r
531         {\r
532             float[] mat = new float[16];\r
533 \r
534             mat[12] = v.X;\r
535             mat[13] = v.Y;\r
536             mat[14] = v.Z;\r
537             mat[0] = mat[5] = mat[10] = mat[15] = 1;\r
538 \r
539             return mat;\r
540         }\r
541 \r
542         public static float[] CreateRotationMatrix(Quaternion q)\r
543         {\r
544             float[] mat = new float[16];\r
545 \r
546             // Transpose the quaternion (don't ask me why)\r
547             q.X = q.X * -1f;\r
548             q.Y = q.Y * -1f;\r
549             q.Z = q.Z * -1f;\r
550 \r
551             float x2 = q.X + q.X;\r
552             float y2 = q.Y + q.Y;\r
553             float z2 = q.Z + q.Z;\r
554             float xx = q.X * x2;\r
555             float xy = q.X * y2;\r
556             float xz = q.X * z2;\r
557             float yy = q.Y * y2;\r
558             float yz = q.Y * z2;\r
559             float zz = q.Z * z2;\r
560             float wx = q.W * x2;\r
561             float wy = q.W * y2;\r
562             float wz = q.W * z2;\r
563 \r
564             mat[0] = 1.0f - (yy + zz);\r
565             mat[1] = xy - wz;\r
566             mat[2] = xz + wy;\r
567             mat[3] = 0.0f;\r
568 \r
569             mat[4] = xy + wz;\r
570             mat[5] = 1.0f - (xx + zz);\r
571             mat[6] = yz - wx;\r
572             mat[7] = 0.0f;\r
573 \r
574             mat[8] = xz - wy;\r
575             mat[9] = yz + wx;\r
576             mat[10] = 1.0f - (xx + yy);\r
577             mat[11] = 0.0f;\r
578 \r
579             mat[12] = 0.0f;\r
580             mat[13] = 0.0f;\r
581             mat[14] = 0.0f;\r
582             mat[15] = 1.0f;\r
583 \r
584             return mat;\r
585         }\r
586 \r
587         public static float[] CreateScaleMatrix(Vector3 v)\r
588         {\r
589             float[] mat = new float[16];\r
590 \r
591             mat[0] = v.X;\r
592             mat[5] = v.Y;\r
593             mat[10] = v.Z;\r
594             mat[15] = 1;\r
595 \r
596             return mat;\r
597         }\r
598 \r
599         public static bool GluProject(OpenTK.Vector3 objPos, OpenTK.Matrix4 modelMatrix, OpenTK.Matrix4 projMatrix, int[] viewport, out OpenTK.Vector3 screenPos)\r
600         {\r
601             OpenTK.Vector4 _in;\r
602             OpenTK.Vector4 _out;\r
603 \r
604             _in.X = objPos.X;\r
605             _in.Y = objPos.Y;\r
606             _in.Z = objPos.Z;\r
607             _in.W = 1.0f;\r
608 \r
609             _out = OpenTK.Vector4.Transform(_in, modelMatrix);\r
610             _in = OpenTK.Vector4.Transform(_out, projMatrix);\r
611 \r
612             if (_in.W <= 0.0)\r
613             {\r
614                 screenPos = OpenTK.Vector3.Zero;\r
615                 return false;\r
616             }\r
617 \r
618             _in.X /= _in.W;\r
619             _in.Y /= _in.W;\r
620             _in.Z /= _in.W;\r
621             /* Map x, y and z to range 0-1 */\r
622             _in.X = _in.X * 0.5f + 0.5f;\r
623             _in.Y = _in.Y * 0.5f + 0.5f;\r
624             _in.Z = _in.Z * 0.5f + 0.5f;\r
625 \r
626             /* Map x,y to viewport */\r
627             _in.X = _in.X * viewport[2] + viewport[0];\r
628             _in.Y = _in.Y * viewport[3] + viewport[1];\r
629 \r
630             screenPos.X = _in.X;\r
631             screenPos.Y = _in.Y;\r
632             screenPos.Z = _in.Z;\r
633 \r
634             return true;\r
635         }\r
636     }\r
637 \r
638     public class attachment_point\r
639     {\r
640         public string name;\r
641         public string joint;\r
642         public Vector3 position;\r
643         public Quaternion rotation;\r
644         public int id;\r
645         public int group;\r
646 \r
647         public GLMesh jointmesh;\r
648         public int jointmeshindex;\r
649 \r
650     }\r
651 \r
652     /// <summary>\r
653     /// Subclass of LindenMesh that adds vertex, index, and texture coordinate\r
654     /// arrays suitable for pushing direct to OpenGL\r
655     /// </summary>\r
656     public class GLMesh : LindenMesh\r
657     {\r
658         /// <summary>\r
659         /// Subclass of LODMesh that adds an index array suitable for pushing\r
660         /// direct to OpenGL\r
661         /// </summary>\r
662         /// \r
663 \r
664         public int teFaceID;\r
665 \r
666         new public class LODMesh : LindenMesh.LODMesh\r
667         {\r
668             public ushort[] Indices;\r
669 \r
670             public override void LoadMesh(string filename)\r
671             {\r
672                 base.LoadMesh(filename);\r
673 \r
674                 // Generate the index array\r
675                 Indices = new ushort[_numFaces * 3];\r
676                 int current = 0;\r
677                 for (int i = 0; i < _numFaces; i++)\r
678                 {\r
679                     Indices[current++] = (ushort)_faces[i].Indices[0];\r
680                     Indices[current++] = (ushort)_faces[i].Indices[1];\r
681                     Indices[current++] = (ushort)_faces[i].Indices[2];\r
682                 }\r
683             }\r
684         }\r
685 \r
686         /// <summary>\r
687         /// \r
688         /// </summary>\r
689         public struct GLData\r
690         {\r
691             public float[] Vertices;\r
692             public ushort[] Indices;\r
693             public float[] TexCoords;\r
694             public Vector3 Center;\r
695         }\r
696 \r
697         public static GLData baseRenderData;\r
698         public GLData RenderData;\r
699 \r
700         public GLMesh(string name)\r
701             : base(name)\r
702         {\r
703         }\r
704 \r
705         public void setMeshPos(Vector3 pos)\r
706         {\r
707             _position = pos;\r
708         }\r
709 \r
710         public void setMeshRot(Vector3 rot)\r
711         {\r
712             _rotationAngles = rot;\r
713         }\r
714 \r
715         public override void LoadMesh(string filename)\r
716         {\r
717             base.LoadMesh(filename);\r
718 \r
719             float minX, minY, minZ;\r
720             minX = minY = minZ = Single.MaxValue;\r
721             float maxX, maxY, maxZ;\r
722             maxX = maxY = maxZ = Single.MinValue;\r
723 \r
724             // Generate the vertex array\r
725             RenderData.Vertices = new float[_numVertices * 3];\r
726             int current = 0;\r
727             for (int i = 0; i < _numVertices; i++)\r
728             {\r
729                 RenderData.Vertices[current++] = _vertices[i].Coord.X;\r
730                 RenderData.Vertices[current++] = _vertices[i].Coord.Y;\r
731                 RenderData.Vertices[current++] = _vertices[i].Coord.Z;\r
732 \r
733                 if (_vertices[i].Coord.X < minX)\r
734                     minX = _vertices[i].Coord.X;\r
735                 else if (_vertices[i].Coord.X > maxX)\r
736                     maxX = _vertices[i].Coord.X;\r
737 \r
738                 if (_vertices[i].Coord.Y < minY)\r
739                     minY = _vertices[i].Coord.Y;\r
740                 else if (_vertices[i].Coord.Y > maxY)\r
741                     maxY = _vertices[i].Coord.Y;\r
742 \r
743                 if (_vertices[i].Coord.Z < minZ)\r
744                     minZ = _vertices[i].Coord.Z;\r
745                 else if (_vertices[i].Coord.Z > maxZ)\r
746                     maxZ = _vertices[i].Coord.Z;\r
747             }\r
748 \r
749             // Calculate the center-point from the bounding box edges\r
750             RenderData.Center = new Vector3((minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2);\r
751 \r
752             // Generate the index array\r
753             RenderData.Indices = new ushort[_numFaces * 3];\r
754             current = 0;\r
755             for (int i = 0; i < _numFaces; i++)\r
756             {\r
757                 RenderData.Indices[current++] = (ushort)_faces[i].Indices[0];\r
758                 RenderData.Indices[current++] = (ushort)_faces[i].Indices[1];\r
759                 RenderData.Indices[current++] = (ushort)_faces[i].Indices[2];\r
760             }\r
761 \r
762             // Generate the texcoord array\r
763             RenderData.TexCoords = new float[_numVertices * 2];\r
764             current = 0;\r
765             for (int i = 0; i < _numVertices; i++)\r
766             {\r
767                 RenderData.TexCoords[current++] = _vertices[i].TexCoord.X;\r
768                 RenderData.TexCoords[current++] = _vertices[i].TexCoord.Y;\r
769             }\r
770         }\r
771 \r
772         public override void LoadLODMesh(int level, string filename)\r
773         {\r
774             LODMesh lod = new LODMesh();\r
775             lod.LoadMesh(filename);\r
776             _lodMeshes[level] = lod;\r
777         }\r
778     }\r
779 \r
780     public class GLAvatar\r
781     {\r
782         public static Dictionary<string, GLMesh> _meshes = new Dictionary<string, GLMesh>();\r
783         public static bool _wireframe = true;\r
784         public static bool _showSkirt = false;\r
785         public static Dictionary<int, attachment_point> attachment_points = new Dictionary<int, attachment_point>();\r
786 \r
787         public static void loadlindenmeshes(string LODfilename)\r
788         {\r
789             Bone.loadbones("avatar_skeleton.xml");\r
790 \r
791             string basedir = Directory.GetCurrentDirectory() + System.IO.Path.DirectorySeparatorChar + "character" + System.IO.Path.DirectorySeparatorChar;\r
792 \r
793             // Parse through avatar_lad.xml to find all of the mesh references\r
794             XmlDocument lad = new XmlDocument();\r
795             lad.Load(basedir + LODfilename);\r
796 \r
797             attachment_points.Clear();\r
798 \r
799             XmlNodeList attach_points = lad.GetElementsByTagName("attachment_point");\r
800             foreach (XmlNode apoint in attach_points)\r
801             {\r
802                 attachment_point point = new attachment_point();\r
803                 point.name = apoint.Attributes.GetNamedItem("name").Value;\r
804                 point.joint = apoint.Attributes.GetNamedItem("joint").Value;\r
805 \r
806                 string pos = apoint.Attributes.GetNamedItem("position").Value;\r
807                 string[] posparts = pos.Split(' ');\r
808                 point.position = new Vector3(float.Parse(posparts[0]), float.Parse(posparts[1]), float.Parse(posparts[2]));\r
809 \r
810                 string rot = apoint.Attributes.GetNamedItem("rotation").Value;\r
811                 string[] rotparts = rot.Split(' ');\r
812                 point.rotation = 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
813 \r
814                 point.id = Int32.Parse(apoint.Attributes.GetNamedItem("id").Value);\r
815                 point.group = Int32.Parse(apoint.Attributes.GetNamedItem("group").Value);\r
816 \r
817                 attachment_points.Add(point.id, point);\r
818 \r
819             }\r
820 \r
821             XmlNodeList bones = lad.GetElementsByTagName("bone");\r
822 \r
823             XmlNodeList meshes = lad.GetElementsByTagName("mesh");\r
824 \r
825             foreach (XmlNode meshNode in meshes)\r
826             {\r
827                 string type = meshNode.Attributes.GetNamedItem("type").Value;\r
828                 int lod = Int32.Parse(meshNode.Attributes.GetNamedItem("lod").Value);\r
829                 string fileName = meshNode.Attributes.GetNamedItem("file_name").Value;\r
830                 //string minPixelWidth = meshNode.Attributes.GetNamedItem("min_pixel_width").Value;\r
831 \r
832                 GLMesh mesh = (_meshes.ContainsKey(type) ? _meshes[type] : new GLMesh(type));\r
833 \r
834                 switch (mesh.Name)\r
835                 {\r
836                     case "lowerBodyMesh":\r
837                         mesh.teFaceID = (int)AvatarTextureIndex.LowerBaked;\r
838                         break;\r
839 \r
840                     case "upperBodyMesh":\r
841                         mesh.teFaceID = (int)AvatarTextureIndex.UpperBaked;\r
842                         break;\r
843 \r
844                     case "headMesh":\r
845                         mesh.teFaceID = (int)AvatarTextureIndex.HeadBaked;\r
846                         break;\r
847 \r
848                     case "hairMesh":\r
849                         mesh.teFaceID = (int)AvatarTextureIndex.HairBaked;\r
850                         break;\r
851 \r
852                     case "eyelashMesh":\r
853                         mesh.teFaceID = (int)AvatarTextureIndex.HeadBaked;\r
854                         break;\r
855 \r
856                     case "eyeBallRightMesh":\r
857                         mesh.setMeshPos(Bone.getOffset("mEyeLeft"));\r
858                         //mesh.setMeshRot(Bone.getRotation("mEyeLeft"));\r
859                         mesh.teFaceID = (int)AvatarTextureIndex.EyesBaked;\r
860                         break;\r
861 \r
862                     case "eyeBallLeftMesh":\r
863                         mesh.setMeshPos(Bone.getOffset("mEyeRight"));\r
864                         //mesh.setMeshRot(Bone.getRotation("mEyeRight"));\r
865                         mesh.teFaceID = (int)AvatarTextureIndex.EyesBaked;\r
866                         break;\r
867 \r
868                     case "skirtMesh":\r
869                         mesh.teFaceID = (int)AvatarTextureIndex.SkirtBaked;\r
870                         break;\r
871 \r
872                     default:\r
873                         mesh.teFaceID = 0;\r
874                         break;\r
875                 }\r
876 \r
877                 if (lod == 0)\r
878                 {\r
879                     mesh.LoadMesh(basedir + fileName);\r
880                 }\r
881                 else\r
882                 {\r
883                     mesh.LoadLODMesh(lod, basedir + fileName);\r
884                 }\r
885 \r
886                 _meshes[type] = mesh;\r
887 \r
888             }\r
889         }\r
890 \r
891     }\r
892 \r
893     class RenderAvatar\r
894     {\r
895         public GLAvatar glavatar;\r
896         public Avatar avatar;\r
897         public FaceData[] data = new FaceData[32];\r
898 \r
899     }\r
900 \r
901     public class Bone\r
902     {\r
903         public string name;\r
904         public Vector3 pos;\r
905         //public Vector3 rot;\r
906         public Quaternion rot;\r
907         public Vector3 scale;\r
908         public Vector3 piviot;\r
909 \r
910         public Bone parent;\r
911 \r
912         public static Dictionary<string, Bone> mBones = new Dictionary<string, Bone>();\r
913 \r
914         public static void loadbones(string skeletonfilename)\r
915         {\r
916             mBones.Clear();\r
917             string basedir = Directory.GetCurrentDirectory() + System.IO.Path.DirectorySeparatorChar + "character" + System.IO.Path.DirectorySeparatorChar;\r
918             XmlDocument skeleton = new XmlDocument();\r
919             skeleton.Load(basedir + skeletonfilename);\r
920             XmlNode boneslist = skeleton.GetElementsByTagName("linden_skeleton")[0];\r
921             addbone(boneslist.ChildNodes[0], null);\r
922         }\r
923 \r
924         public static void addbone(XmlNode bone, Bone parent)\r
925         {\r
926             Bone b = new Bone();\r
927             b.name = bone.Attributes.GetNamedItem("name").Value;\r
928 \r
929             string pos = bone.Attributes.GetNamedItem("pos").Value;\r
930             string[] posparts = pos.Split(' ');\r
931             b.pos = new Vector3(float.Parse(posparts[0]), float.Parse(posparts[1]), float.Parse(posparts[2]));\r
932 \r
933             string rot = bone.Attributes.GetNamedItem("rot").Value;\r
934             string[] rotparts = pos.Split(' ');\r
935             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
936 \r
937             string scale = bone.Attributes.GetNamedItem("scale").Value;\r
938             string[] scaleparts = pos.Split(' ');\r
939             b.scale = new Vector3(float.Parse(scaleparts[0]), float.Parse(scaleparts[1]), float.Parse(scaleparts[2]));\r
940 \r
941             //TODO piviot\r
942 \r
943             b.parent = parent;\r
944 \r
945             mBones.Add(b.name, b);\r
946 \r
947             Logger.Log("Found bone " + b.name, Helpers.LogLevel.Info);\r
948 \r
949             foreach (XmlNode childbone in bone.ChildNodes)\r
950             {\r
951                 addbone(childbone, b);\r
952             }\r
953 \r
954         }\r
955 \r
956         //TODO check offset and rot calcuations should each offset be multiplied by its parent rotation in\r
957         // a standard child/parent rot/offset way?\r
958         public static Vector3 getOffset(string bonename)\r
959         {\r
960             Bone b;\r
961             if (mBones.TryGetValue(bonename, out b))\r
962             {\r
963                 return (b.getOffset());\r
964             }\r
965             else\r
966             {\r
967                 return Vector3.Zero;\r
968             }\r
969         }\r
970 \r
971         public Vector3 getOffset()\r
972         {\r
973             Vector3 totalpos = pos;\r
974 \r
975             if (parent != null)\r
976             {\r
977                 totalpos = parent.getOffset() + pos;\r
978             }\r
979 \r
980             return totalpos;\r
981         }\r
982 \r
983         public static Quaternion getRotation(string bonename)\r
984         {\r
985             Bone b;\r
986             if (mBones.TryGetValue(bonename, out b))\r
987             {\r
988                 return (b.getRotation());\r
989             }\r
990             else\r
991             {\r
992                 return Quaternion.Identity;\r
993             }\r
994         }\r
995 \r
996         public Quaternion getRotation()\r
997         {\r
998             Quaternion totalrot = rot;\r
999 \r
1000             if (parent != null)\r
1001             {\r
1002                 totalrot = parent.getRotation() * rot;\r
1003             }\r
1004 \r
1005             return totalrot;\r
1006         }\r
1007 \r
1008     }\r
1009 \r
1010 }\r