2 using System.Collections.Generic;
\r
7 using OpenTK.Graphics.OpenGL;
\r
8 using System.Runtime.InteropServices;
\r
10 using OpenMetaverse.Rendering;
\r
12 namespace Radegast.Rendering
\r
14 public class FaceData
\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
28 public void CheckVBO(Face face)
\r
30 if (VertexVBO == -1)
\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
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
48 public class TextureAnimationInfo
\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
57 public void Step(double lastFrameTime)
\r
59 float numFrames = 1f;
\r
60 float fullLength = 1f;
\r
62 if (PrimAnimInfo.Length > 0)
\r
64 numFrames = PrimAnimInfo.Length;
\r
68 numFrames = Math.Max(1f, (float)(PrimAnimInfo.SizeX * PrimAnimInfo.SizeY));
\r
71 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.PING_PONG) != 0)
\r
73 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)
\r
75 fullLength = 2f * numFrames;
\r
77 else if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.LOOP) != 0)
\r
79 fullLength = 2f * numFrames - 2f;
\r
80 fullLength = Math.Max(1f, fullLength);
\r
84 fullLength = 2f * numFrames - 1f;
\r
85 fullLength = Math.Max(1f, fullLength);
\r
90 fullLength = numFrames;
\r
94 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)
\r
96 frameCounter = (float)lastFrameTime * PrimAnimInfo.Rate + LastTime;
\r
100 TotalTime += (float)lastFrameTime;
\r
101 frameCounter = TotalTime * PrimAnimInfo.Rate;
\r
103 LastTime = frameCounter;
\r
105 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.LOOP) != 0)
\r
107 frameCounter %= fullLength;
\r
111 frameCounter = Math.Min(fullLength - 1f, frameCounter);
\r
114 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) == 0)
\r
116 frameCounter = (float)Math.Floor(frameCounter + 0.01f);
\r
119 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.PING_PONG) != 0)
\r
121 if (frameCounter > numFrames)
\r
123 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)
\r
125 frameCounter = numFrames - (frameCounter - numFrames);
\r
129 frameCounter = (numFrames - 1.99f) - (frameCounter - numFrames);
\r
134 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.REVERSE) != 0)
\r
136 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)
\r
138 frameCounter = numFrames - frameCounter;
\r
142 frameCounter = (numFrames - 0.99f) - frameCounter;
\r
146 frameCounter += PrimAnimInfo.Start;
\r
148 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) == 0)
\r
150 frameCounter = (float)Math.Round(frameCounter);
\r
154 GL.MatrixMode(MatrixMode.Texture);
\r
157 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.ROTATE) != 0)
\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
163 else if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SCALE) != 0)
\r
165 GL.Scale(frameCounter, frameCounter, 0);
\r
169 float sizeX = Math.Max(1f, (float)PrimAnimInfo.SizeX);
\r
170 float sizeY = Math.Max(1f, (float)PrimAnimInfo.SizeY);
\r
172 GL.Scale(1f / sizeX, 1f / sizeY, 0);
\r
173 GL.Translate(frameCounter % sizeX, Math.Floor(frameCounter / sizeY), 0);
\r
176 GL.MatrixMode(MatrixMode.Modelview);
\r
179 [Obsolete("Use Step() instead")]
\r
180 public void ExperimentalStep(double time)
\r
182 int reverseFactor = 1;
\r
183 float rate = PrimAnimInfo.Rate;
\r
188 reverseFactor = -reverseFactor;
\r
191 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.REVERSE) != 0)
\r
193 reverseFactor = -reverseFactor;
\r
196 CurrentTime += time;
\r
197 double totalTime = 1 / rate;
\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
203 if (PrimAnimInfo.Length > 0 && PrimAnimInfo.Length < nrFrames)
\r
205 nrFrames = (uint)PrimAnimInfo.Length;
\r
208 GL.MatrixMode(MatrixMode.Texture);
\r
211 if (CurrentTime >= totalTime)
\r
215 if (CurrentFrame > nrFrames) CurrentFrame = (uint)PrimAnimInfo.Start;
\r
216 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.PING_PONG) != 0)
\r
218 PingPong = !PingPong;
\r
222 float smoothOffset = 0f;
\r
224 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.SMOOTH) != 0)
\r
226 smoothOffset = (float)(CurrentTime / totalTime) * reverseFactor;
\r
229 float f = CurrentFrame;
\r
230 if (reverseFactor < 0)
\r
232 f = nrFrames - CurrentFrame;
\r
235 if ((PrimAnimInfo.Flags & Primitive.TextureAnimMode.ROTATE) == 0) // not rotaating
\r
237 GL.Scale(1f / x, 1f / y, 0f);
\r
238 GL.Translate((f % x) + smoothOffset, f / y, 0);
\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
251 GL.MatrixMode(MatrixMode.Modelview);
\r
257 public class TextureInfo
\r
259 public System.Drawing.Image Texture;
\r
260 public int TexturePointer;
\r
261 public bool HasAlpha;
\r
262 public UUID TextureID;
\r
265 public class TextureLoadItem
\r
267 public FaceData Data;
\r
268 public Primitive Prim;
\r
269 public Primitive.TextureEntryFace TeFace;
\r
272 public enum RenderPass
\r
279 public static class Render
\r
281 public static IRendering Plugin;
\r
284 public static class RHelp
\r
286 public static OpenTK.Vector2 TKVector3(Vector2 v)
\r
288 return new OpenTK.Vector2(v.X, v.Y);
\r
291 public static OpenTK.Vector3 TKVector3(Vector3 v)
\r
293 return new OpenTK.Vector3(v.X, v.Y, v.Z);
\r
296 public static OpenTK.Vector4 TKVector3(Vector4 v)
\r
298 return new OpenTK.Vector4(v.X, v.Y, v.Z, v.W);
\r
303 /// Represents camera object
\r
305 public class Camera
\r
308 Vector3 mFocalPoint;
\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
317 /// <summary>Draw distance</summary>
\r
319 /// <summary>Has camera been modified</summary>
\r
320 public bool Modified { get { return mModified; } set { mModified = value; } }
\r
322 public double TimeToTarget = 0d;
\r
324 public Vector3 RenderPosition;
\r
325 public Vector3 RenderFocalPoint;
\r
330 if (TimeToTarget <= 0)
\r
332 RenderPosition = Position;
\r
333 RenderFocalPoint = FocalPoint;
\r
337 public void Step(double time)
\r
339 TimeToTarget -= time;
\r
340 if (TimeToTarget <= time)
\r
348 float pctElapsed = (float)(time / TimeToTarget);
\r
350 if (RenderPosition != Position)
\r
352 float distance = Vector3.Distance(RenderPosition, Position);
\r
353 RenderPosition = Vector3.Lerp(RenderPosition, Position, (float)(distance * pctElapsed));
\r
356 if (RenderFocalPoint != FocalPoint)
\r
358 RenderFocalPoint = Interpolate(RenderFocalPoint, FocalPoint, pctElapsed);
\r
362 Vector3 Interpolate(Vector3 start, Vector3 end, float fraction)
\r
364 float distance = Vector3.Distance(start, end);
\r
365 Vector3 direction = end - start;
\r
366 return start + direction * fraction;
\r
369 public void EndMove()
\r
373 RenderPosition = Position;
\r
374 RenderFocalPoint = FocalPoint;
\r
378 public static class MeshToOBJ
\r
380 public static bool MeshesToOBJ(Dictionary<uint, FacetedMesh> meshes, string filename)
\r
382 StringBuilder obj = new StringBuilder();
\r
383 StringBuilder mtl = new StringBuilder();
\r
385 FileInfo objFileInfo = new FileInfo(filename);
\r
387 string mtlFilename = objFileInfo.FullName.Substring(objFileInfo.DirectoryName.Length + 1,
\r
388 objFileInfo.FullName.Length - (objFileInfo.DirectoryName.Length + 1) - 4) + ".mtl";
\r
390 obj.AppendLine("# Created by libprimrender");
\r
391 obj.AppendLine("mtllib ./" + mtlFilename);
\r
394 mtl.AppendLine("# Created by libprimrender");
\r
398 foreach (FacetedMesh mesh in meshes.Values)
\r
400 for (int j = 0; j < mesh.Faces.Count; j++)
\r
402 Face face = mesh.Faces[j];
\r
404 if (face.Vertices.Count > 2)
\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
410 // FIXME: Convert the source to TGA (if needed) and copy to the destination
\r
412 float shiny = 0.00f;
\r
415 case Shininess.High:
\r
418 case Shininess.Medium:
\r
421 case Shininess.Low:
\r
426 obj.AppendFormat("g face{0}-{1}{2}", primNr, face.ID, Environment.NewLine);
\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
439 // Write the vertices, texture coordinates, and vertex normals for this side
\r
440 for (int k = 0; k < face.Vertices.Count; k++)
\r
442 Vertex vertex = face.Vertices[k];
\r
446 Vector3 pos = vertex.Position;
\r
449 pos *= mesh.Prim.Scale;
\r
452 pos *= mesh.Prim.Rotation;
\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
460 obj.AppendFormat("v {0} {1} {2}{3}", pos.X, pos.Y, pos.Z, Environment.NewLine);
\r
464 #region Texture Coord
\r
466 obj.AppendFormat("vt {0} {1}{2}", vertex.TexCoord.X, vertex.TexCoord.Y,
\r
467 Environment.NewLine);
\r
469 #endregion Texture Coord
\r
471 #region Vertex Normal
\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
478 obj.AppendLine("vn 0.0 1.0 0.0");
\r
480 #endregion Vertex Normal
\r
483 obj.AppendFormat("# {0} vertices{1}", face.Vertices.Count, Environment.NewLine);
\r
485 obj.AppendLine("usemtl " + mtlName);
\r
489 // Write all of the faces (triangles) for this side
\r
490 for (int k = 0; k < face.Indices.Count / 3; k++)
\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
499 obj.AppendFormat("# {0} elements{1}", face.Indices.Count / 3, Environment.NewLine);
\r
502 #endregion Elements
\r
510 File.WriteAllText(filename, obj.ToString());
\r
511 File.WriteAllText(mtlFilename, mtl.ToString());
\r
522 public static class Math3D
\r
530 public static float[] CreateTranslationMatrix(Vector3 v)
\r
532 float[] mat = new float[16];
\r
537 mat[0] = mat[5] = mat[10] = mat[15] = 1;
\r
542 public static float[] CreateRotationMatrix(Quaternion q)
\r
544 float[] mat = new float[16];
\r
546 // Transpose the quaternion (don't ask me why)
\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
564 mat[0] = 1.0f - (yy + zz);
\r
570 mat[5] = 1.0f - (xx + zz);
\r
576 mat[10] = 1.0f - (xx + yy);
\r
587 public static float[] CreateScaleMatrix(Vector3 v)
\r
589 float[] mat = new float[16];
\r
599 public static bool GluProject(OpenTK.Vector3 objPos, OpenTK.Matrix4 modelMatrix, OpenTK.Matrix4 projMatrix, int[] viewport, out OpenTK.Vector3 screenPos)
\r
601 OpenTK.Vector4 _in;
\r
602 OpenTK.Vector4 _out;
\r
609 _out = OpenTK.Vector4.Transform(_in, modelMatrix);
\r
610 _in = OpenTK.Vector4.Transform(_out, projMatrix);
\r
614 screenPos = OpenTK.Vector3.Zero;
\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
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
630 screenPos.X = _in.X;
\r
631 screenPos.Y = _in.Y;
\r
632 screenPos.Z = _in.Z;
\r
638 public class attachment_point
\r
640 public string name;
\r
641 public string joint;
\r
642 public Vector3 position;
\r
643 public Quaternion rotation;
\r
647 public GLMesh jointmesh;
\r
648 public int jointmeshindex;
\r
653 /// Subclass of LindenMesh that adds vertex, index, and texture coordinate
\r
654 /// arrays suitable for pushing direct to OpenGL
\r
656 public class GLMesh : LindenMesh
\r
659 /// Subclass of LODMesh that adds an index array suitable for pushing
\r
660 /// direct to OpenGL
\r
664 public int teFaceID;
\r
666 new public class LODMesh : LindenMesh.LODMesh
\r
668 public ushort[] Indices;
\r
670 public override void LoadMesh(string filename)
\r
672 base.LoadMesh(filename);
\r
674 // Generate the index array
\r
675 Indices = new ushort[_numFaces * 3];
\r
677 for (int i = 0; i < _numFaces; i++)
\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
689 public struct GLData
\r
691 public float[] Vertices;
\r
692 public ushort[] Indices;
\r
693 public float[] TexCoords;
\r
694 public Vector3 Center;
\r
697 public static GLData baseRenderData;
\r
698 public GLData RenderData;
\r
700 public GLMesh(string name)
\r
705 public void setMeshPos(Vector3 pos)
\r
710 public void setMeshRot(Vector3 rot)
\r
712 _rotationAngles = rot;
\r
715 public override void LoadMesh(string filename)
\r
717 base.LoadMesh(filename);
\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
724 // Generate the vertex array
\r
725 RenderData.Vertices = new float[_numVertices * 3];
\r
727 for (int i = 0; i < _numVertices; i++)
\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
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
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
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
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
752 // Generate the index array
\r
753 RenderData.Indices = new ushort[_numFaces * 3];
\r
755 for (int i = 0; i < _numFaces; i++)
\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
762 // Generate the texcoord array
\r
763 RenderData.TexCoords = new float[_numVertices * 2];
\r
765 for (int i = 0; i < _numVertices; i++)
\r
767 RenderData.TexCoords[current++] = _vertices[i].TexCoord.X;
\r
768 RenderData.TexCoords[current++] = _vertices[i].TexCoord.Y;
\r
772 public override void LoadLODMesh(int level, string filename)
\r
774 LODMesh lod = new LODMesh();
\r
775 lod.LoadMesh(filename);
\r
776 _lodMeshes[level] = lod;
\r
780 public class GLAvatar
\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
787 public static void loadlindenmeshes(string LODfilename)
\r
789 Bone.loadbones("avatar_skeleton.xml");
\r
791 string basedir = Directory.GetCurrentDirectory() + System.IO.Path.DirectorySeparatorChar + "character" + System.IO.Path.DirectorySeparatorChar;
\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
797 attachment_points.Clear();
\r
799 XmlNodeList attach_points = lad.GetElementsByTagName("attachment_point");
\r
800 foreach (XmlNode apoint in attach_points)
\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
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
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
814 point.id = Int32.Parse(apoint.Attributes.GetNamedItem("id").Value);
\r
815 point.group = Int32.Parse(apoint.Attributes.GetNamedItem("group").Value);
\r
817 attachment_points.Add(point.id, point);
\r
821 XmlNodeList bones = lad.GetElementsByTagName("bone");
\r
823 XmlNodeList meshes = lad.GetElementsByTagName("mesh");
\r
825 foreach (XmlNode meshNode in meshes)
\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
832 GLMesh mesh = (_meshes.ContainsKey(type) ? _meshes[type] : new GLMesh(type));
\r
836 case "lowerBodyMesh":
\r
837 mesh.teFaceID = (int)AvatarTextureIndex.LowerBaked;
\r
840 case "upperBodyMesh":
\r
841 mesh.teFaceID = (int)AvatarTextureIndex.UpperBaked;
\r
845 mesh.teFaceID = (int)AvatarTextureIndex.HeadBaked;
\r
849 mesh.teFaceID = (int)AvatarTextureIndex.HairBaked;
\r
852 case "eyelashMesh":
\r
853 mesh.teFaceID = (int)AvatarTextureIndex.HeadBaked;
\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
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
869 mesh.teFaceID = (int)AvatarTextureIndex.SkirtBaked;
\r
879 mesh.LoadMesh(basedir + fileName);
\r
883 mesh.LoadLODMesh(lod, basedir + fileName);
\r
886 _meshes[type] = mesh;
\r
895 public GLAvatar glavatar;
\r
896 public Avatar avatar;
\r
897 public FaceData[] data = new FaceData[32];
\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
910 public Bone parent;
\r
912 public static Dictionary<string, Bone> mBones = new Dictionary<string, Bone>();
\r
914 public static void loadbones(string skeletonfilename)
\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
924 public static void addbone(XmlNode bone, Bone parent)
\r
926 Bone b = new Bone();
\r
927 b.name = bone.Attributes.GetNamedItem("name").Value;
\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
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
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
945 mBones.Add(b.name, b);
\r
947 Logger.Log("Found bone " + b.name, Helpers.LogLevel.Info);
\r
949 foreach (XmlNode childbone in bone.ChildNodes)
\r
951 addbone(childbone, b);
\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
961 if (mBones.TryGetValue(bonename, out b))
\r
963 return (b.getOffset());
\r
967 return Vector3.Zero;
\r
971 public Vector3 getOffset()
\r
973 Vector3 totalpos = pos;
\r
975 if (parent != null)
\r
977 totalpos = parent.getOffset() + pos;
\r
983 public static Quaternion getRotation(string bonename)
\r
986 if (mBones.TryGetValue(bonename, out b))
\r
988 return (b.getRotation());
\r
992 return Quaternion.Identity;
\r
996 public Quaternion getRotation()
\r
998 Quaternion totalrot = rot;
\r
1000 if (parent != null)
\r
1002 totalrot = parent.getRotation() * rot;
\r