OSDN Git Service

Update copyright year
[radegast/radegast.git] / Radegast / GUI / Rendering / RenderingHelpers.cs
index 618b758..1bce425 100644 (file)
-using System;\r
-using System.Collections.Generic;\r
-using System.Linq;\r
-using System.Text;\r
-using System.IO;\r
-using System.Xml;\r
-using OpenTK.Graphics.OpenGL;\r
-using System.Runtime.InteropServices;\r
-using OpenMetaverse;\r
-using OpenMetaverse.Rendering;\r
-\r
-namespace Radegast.Rendering\r
-{\r
-    public class FaceData\r
-    {\r
-        public float[] Vertices;\r
-        public ushort[] Indices;\r
-        public float[] TexCoords;\r
-        public float[] Normals;\r
-        public int PickingID = -1;\r
-        public int VertexVBO = -1;\r
-        public int IndexVBO = -1;\r
-        public TextureInfo TextureInfo = new TextureInfo();\r
-        public BoundingSphere BoundingSphere = new BoundingSphere();\r
-        public static int VertexSize = 32; // sizeof (vertex), 2  x vector3 + 1 x vector2 = 8 floats x 4 bytes = 32 bytes \r
-        \r
-        public void CheckVBO(Face face)\r
-        {\r
-            if (VertexVBO == -1)\r
-            {\r
-                Vertex[] vArray = face.Vertices.ToArray();\r
-                GL.GenBuffers(1, out VertexVBO);\r
-                GL.BindBuffer(BufferTarget.ArrayBuffer, VertexVBO);\r
-                GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vArray.Length * VertexSize), vArray, BufferUsageHint.StreamDraw);\r
-            }\r
-\r
-            if (IndexVBO == -1)\r
-            {\r
-                ushort[] iArray = face.Indices.ToArray();\r
-                GL.GenBuffers(1, out IndexVBO);\r
-                GL.BindBuffer(BufferTarget.ElementArrayBuffer, IndexVBO);\r
-                GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(iArray.Length * sizeof(ushort)), iArray, BufferUsageHint.StreamDraw);\r
-            }\r
-        }\r
-    }\r
-\r
-    public class TextureInfo\r
-    {\r
-        public System.Drawing.Image Texture;\r
-        public int TexturePointer;\r
-        public bool HasAlpha;\r
-        public UUID TextureID;\r
-    }\r
-\r
-    public class TextureLoadItem\r
-    {\r
-        public FaceData Data;\r
-        public Primitive Prim;\r
-        public Primitive.TextureEntryFace TeFace;\r
-    }\r
-\r
-    public enum RenderPass\r
-    {\r
-        Picking,\r
-        Simple,\r
-        Alpha\r
-    }\r
-\r
-    public static class Render\r
-    {\r
-        public static IRendering Plugin;\r
-    }\r
-\r
-    public static class RHelp\r
-    {\r
-        public static OpenTK.Vector2 TKVector3(Vector2 v)\r
-        {\r
-            return new OpenTK.Vector2(v.X, v.Y);\r
-        }\r
-\r
-        public static OpenTK.Vector3 TKVector3(Vector3 v)\r
-        {\r
-            return new OpenTK.Vector3(v.X, v.Y, v.Z);\r
-        }\r
-\r
-        public static OpenTK.Vector4 TKVector3(Vector4 v)\r
-        {\r
-            return new OpenTK.Vector4(v.X, v.Y, v.Z, v.W);\r
-        }\r
-    }\r
-\r
-    /// <summary>\r
-    /// Represents camera object\r
-    /// </summary>\r
-    public struct Camera\r
-    {\r
-        Vector3 mPosition;\r
-        Vector3 mFocalPoint;\r
-        bool mModified;\r
-        \r
-        /// <summary>Camera position</summary>\r
-        public Vector3 Position { get { return mPosition; } set { mPosition = value; mModified = true; } }\r
-        /// <summary>Camera target</summary>\r
-        public Vector3 FocalPoint { get { return mFocalPoint; } set { mFocalPoint = value; mModified = true; } }\r
-        /// <summary>Zoom level</summary>\r
-        public float Zoom;\r
-        /// <summary>Draw distance</summary>\r
-        public float Far;\r
-        /// <summary>Has camera been modified</summary>\r
-        public bool Modified { get { return mModified; } set { mModified = value; } }\r
-    }\r
-\r
-    public static class MeshToOBJ\r
-    {\r
-        public static bool MeshesToOBJ(Dictionary<uint, FacetedMesh> meshes, string filename)\r
-        {\r
-            StringBuilder obj = new StringBuilder();\r
-            StringBuilder mtl = new StringBuilder();\r
-\r
-            FileInfo objFileInfo = new FileInfo(filename);\r
-\r
-            string mtlFilename = objFileInfo.FullName.Substring(objFileInfo.DirectoryName.Length + 1,\r
-                objFileInfo.FullName.Length - (objFileInfo.DirectoryName.Length + 1) - 4) + ".mtl";\r
-\r
-            obj.AppendLine("# Created by libprimrender");\r
-            obj.AppendLine("mtllib ./" + mtlFilename);\r
-            obj.AppendLine();\r
-\r
-            mtl.AppendLine("# Created by libprimrender");\r
-            mtl.AppendLine();\r
-\r
-            int primNr = 0;\r
-            foreach (FacetedMesh mesh in meshes.Values)\r
-            {\r
-                for (int j = 0; j < mesh.Faces.Count; j++)\r
-                {\r
-                    Face face = mesh.Faces[j];\r
-\r
-                    if (face.Vertices.Count > 2)\r
-                    {\r
-                        string mtlName = String.Format("material{0}-{1}", primNr, face.ID);\r
-                        Primitive.TextureEntryFace tex = face.TextureFace;\r
-                        string texName = tex.TextureID.ToString() + ".tga";\r
-\r
-                        // FIXME: Convert the source to TGA (if needed) and copy to the destination\r
-\r
-                        float shiny = 0.00f;\r
-                        switch (tex.Shiny)\r
-                        {\r
-                            case Shininess.High:\r
-                                shiny = 1.00f;\r
-                                break;\r
-                            case Shininess.Medium:\r
-                                shiny = 0.66f;\r
-                                break;\r
-                            case Shininess.Low:\r
-                                shiny = 0.33f;\r
-                                break;\r
-                        }\r
-\r
-                        obj.AppendFormat("g face{0}-{1}{2}", primNr, face.ID, Environment.NewLine);\r
-\r
-                        mtl.AppendLine("newmtl " + mtlName);\r
-                        mtl.AppendFormat("Ka {0} {1} {2}{3}", tex.RGBA.R, tex.RGBA.G, tex.RGBA.B, Environment.NewLine);\r
-                        mtl.AppendFormat("Kd {0} {1} {2}{3}", tex.RGBA.R, tex.RGBA.G, tex.RGBA.B, Environment.NewLine);\r
-                        //mtl.AppendFormat("Ks {0} {1} {2}{3}");\r
-                        mtl.AppendLine("Tr " + tex.RGBA.A);\r
-                        mtl.AppendLine("Ns " + shiny);\r
-                        mtl.AppendLine("illum 1");\r
-                        if (tex.TextureID != UUID.Zero && tex.TextureID != Primitive.TextureEntry.WHITE_TEXTURE)\r
-                            mtl.AppendLine("map_Kd ./" + texName);\r
-                        mtl.AppendLine();\r
-\r
-                        // Write the vertices, texture coordinates, and vertex normals for this side\r
-                        for (int k = 0; k < face.Vertices.Count; k++)\r
-                        {\r
-                            Vertex vertex = face.Vertices[k];\r
-\r
-                            #region Vertex\r
-\r
-                            Vector3 pos = vertex.Position;\r
-\r
-                            // Apply scaling\r
-                            pos *= mesh.Prim.Scale;\r
-\r
-                            // Apply rotation\r
-                            pos *= mesh.Prim.Rotation;\r
-\r
-                            // The root prim position is sim-relative, while child prim positions are\r
-                            // parent-relative. We want to apply parent-relative translations but not\r
-                            // sim-relative ones\r
-                            if (mesh.Prim.ParentID != 0)\r
-                                pos += mesh.Prim.Position;\r
-\r
-                            obj.AppendFormat("v {0} {1} {2}{3}", pos.X, pos.Y, pos.Z, Environment.NewLine);\r
-\r
-                            #endregion Vertex\r
-\r
-                            #region Texture Coord\r
-\r
-                            obj.AppendFormat("vt {0} {1}{2}", vertex.TexCoord.X, vertex.TexCoord.Y,\r
-                                Environment.NewLine);\r
-\r
-                            #endregion Texture Coord\r
-\r
-                            #region Vertex Normal\r
-\r
-                            // HACK: Sometimes normals are getting set to <NaN,NaN,NaN>\r
-                            if (!Single.IsNaN(vertex.Normal.X) && !Single.IsNaN(vertex.Normal.Y) && !Single.IsNaN(vertex.Normal.Z))\r
-                                obj.AppendFormat("vn {0} {1} {2}{3}", vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z,\r
-                                    Environment.NewLine);\r
-                            else\r
-                                obj.AppendLine("vn 0.0 1.0 0.0");\r
-\r
-                            #endregion Vertex Normal\r
-                        }\r
-\r
-                        obj.AppendFormat("# {0} vertices{1}", face.Vertices.Count, Environment.NewLine);\r
-                        obj.AppendLine();\r
-                        obj.AppendLine("usemtl " + mtlName);\r
-\r
-                        #region Elements\r
-\r
-                        // Write all of the faces (triangles) for this side\r
-                        for (int k = 0; k < face.Indices.Count / 3; k++)\r
-                        {\r
-                            obj.AppendFormat("f -{0}/-{0}/-{0} -{1}/-{1}/-{1} -{2}/-{2}/-{2}{3}",\r
-                                face.Vertices.Count - face.Indices[k * 3 + 0],\r
-                                face.Vertices.Count - face.Indices[k * 3 + 1],\r
-                                face.Vertices.Count - face.Indices[k * 3 + 2],\r
-                                Environment.NewLine);\r
-                        }\r
-\r
-                        obj.AppendFormat("# {0} elements{1}", face.Indices.Count / 3, Environment.NewLine);\r
-                        obj.AppendLine();\r
-\r
-                        #endregion Elements\r
-                    }\r
-                }\r
-                primNr++;\r
-            }\r
-\r
-            try\r
-            {\r
-                File.WriteAllText(filename, obj.ToString());\r
-                File.WriteAllText(mtlFilename, mtl.ToString());\r
-            }\r
-            catch (Exception)\r
-            {\r
-                return false;\r
-            }\r
-\r
-            return true;\r
-        }\r
-    }\r
-\r
-    public static class Math3D\r
-    {\r
-        // Column-major:\r
-        // |  0  4  8 12 |\r
-        // |  1  5  9 13 |\r
-        // |  2  6 10 14 |\r
-        // |  3  7 11 15 |\r
-\r
-        public static float[] CreateTranslationMatrix(Vector3 v)\r
-        {\r
-            float[] mat = new float[16];\r
-\r
-            mat[12] = v.X;\r
-            mat[13] = v.Y;\r
-            mat[14] = v.Z;\r
-            mat[0] = mat[5] = mat[10] = mat[15] = 1;\r
-\r
-            return mat;\r
-        }\r
-\r
-        public static float[] CreateRotationMatrix(Quaternion q)\r
-        {\r
-            float[] mat = new float[16];\r
-\r
-            // Transpose the quaternion (don't ask me why)\r
-            q.X = q.X * -1f;\r
-            q.Y = q.Y * -1f;\r
-            q.Z = q.Z * -1f;\r
-\r
-            float x2 = q.X + q.X;\r
-            float y2 = q.Y + q.Y;\r
-            float z2 = q.Z + q.Z;\r
-            float xx = q.X * x2;\r
-            float xy = q.X * y2;\r
-            float xz = q.X * z2;\r
-            float yy = q.Y * y2;\r
-            float yz = q.Y * z2;\r
-            float zz = q.Z * z2;\r
-            float wx = q.W * x2;\r
-            float wy = q.W * y2;\r
-            float wz = q.W * z2;\r
-\r
-            mat[0] = 1.0f - (yy + zz);\r
-            mat[1] = xy - wz;\r
-            mat[2] = xz + wy;\r
-            mat[3] = 0.0f;\r
-\r
-            mat[4] = xy + wz;\r
-            mat[5] = 1.0f - (xx + zz);\r
-            mat[6] = yz - wx;\r
-            mat[7] = 0.0f;\r
-\r
-            mat[8] = xz - wy;\r
-            mat[9] = yz + wx;\r
-            mat[10] = 1.0f - (xx + yy);\r
-            mat[11] = 0.0f;\r
-\r
-            mat[12] = 0.0f;\r
-            mat[13] = 0.0f;\r
-            mat[14] = 0.0f;\r
-            mat[15] = 1.0f;\r
-\r
-            return mat;\r
-        }\r
-\r
-        public static float[] CreateScaleMatrix(Vector3 v)\r
-        {\r
-            float[] mat = new float[16];\r
-\r
-            mat[0] = v.X;\r
-            mat[5] = v.Y;\r
-            mat[10] = v.Z;\r
-            mat[15] = 1;\r
-\r
-            return mat;\r
-        }\r
-\r
-        public static bool GluProject(OpenTK.Vector3 objPos, OpenTK.Matrix4 modelMatrix, OpenTK.Matrix4 projMatrix, int[] viewport, out OpenTK.Vector3 screenPos)\r
-        {\r
-            OpenTK.Vector4 _in;\r
-            OpenTK.Vector4 _out;\r
-\r
-            _in.X = objPos.X;\r
-            _in.Y = objPos.Y;\r
-            _in.Z = objPos.Z;\r
-            _in.W = 1.0f;\r
-\r
-            _out = OpenTK.Vector4.Transform(_in, modelMatrix);\r
-            _in = OpenTK.Vector4.Transform(_out, projMatrix);\r
-\r
-            if (_in.W <= 0.0)\r
-            {\r
-                screenPos = OpenTK.Vector3.Zero;\r
-                return false;\r
-            }\r
-\r
-            _in.X /= _in.W;\r
-            _in.Y /= _in.W;\r
-            _in.Z /= _in.W;\r
-            /* Map x, y and z to range 0-1 */\r
-            _in.X = _in.X * 0.5f + 0.5f;\r
-            _in.Y = _in.Y * 0.5f + 0.5f;\r
-            _in.Z = _in.Z * 0.5f + 0.5f;\r
-\r
-            /* Map x,y to viewport */\r
-            _in.X = _in.X * viewport[2] + viewport[0];\r
-            _in.Y = _in.Y * viewport[3] + viewport[1];\r
-\r
-            screenPos.X = _in.X;\r
-            screenPos.Y = _in.Y;\r
-            screenPos.Z = _in.Z;\r
-\r
-            return true;\r
-        }\r
-    }\r
-\r
-    public class attachment_point\r
-    {\r
-        public string name;\r
-        public string joint;\r
-        public Vector3 position;\r
-        public Vector3 rotation;\r
-        public int id;\r
-        public int group;\r
-\r
-        public GLMesh jointmesh;\r
-        public int jointmeshindex;\r
-\r
-        public Vector3 getposition()\r
-        {\r
-            Vector3 pos;\r
-            pos = jointmesh.Position + position;\r
-            return pos;\r
-        }\r
-\r
-        public Quaternion getrotation()\r
-        {\r
-            Vector3 rotvec = jointmesh.RotationAngles + rotation;\r
-            rotvec.Normalize();\r
-            Quaternion rot = new Quaternion(rotvec.X, rotvec.Y, rotvec.Z);\r
-            return rot;\r
-        }\r
-    }\r
-\r
-    /// <summary>\r
-    /// Subclass of LindenMesh that adds vertex, index, and texture coordinate\r
-    /// arrays suitable for pushing direct to OpenGL\r
-    /// </summary>\r
-    public class GLMesh : LindenMesh\r
-    {\r
-        /// <summary>\r
-        /// Subclass of LODMesh that adds an index array suitable for pushing\r
-        /// direct to OpenGL\r
-        /// </summary>\r
-        /// \r
-\r
-        public int teFaceID;\r
-\r
-        new public class LODMesh : LindenMesh.LODMesh\r
-        {\r
-            public ushort[] Indices;\r
-\r
-            public override void LoadMesh(string filename)\r
-            {\r
-                base.LoadMesh(filename);\r
-\r
-                // Generate the index array\r
-                Indices = new ushort[_numFaces * 3];\r
-                int current = 0;\r
-                for (int i = 0; i < _numFaces; i++)\r
-                {\r
-                    Indices[current++] = (ushort)_faces[i].Indices[0];\r
-                    Indices[current++] = (ushort)_faces[i].Indices[1];\r
-                    Indices[current++] = (ushort)_faces[i].Indices[2];\r
-                }\r
-            }\r
-        }\r
-\r
-        /// <summary>\r
-        /// \r
-        /// </summary>\r
-        public struct GLData\r
-        {\r
-            public float[] Vertices;\r
-            public ushort[] Indices;\r
-            public float[] TexCoords;\r
-            public Vector3 Center;\r
-        }\r
-\r
-        public static GLData baseRenderData;\r
-        public GLData RenderData;\r
-\r
-        public GLMesh(string name)\r
-            : base(name)\r
-        {\r
-        }\r
-\r
-        public void setMeshPos(Vector3 pos)\r
-        {\r
-            _position = pos;\r
-        }\r
-\r
-        public void setMeshRot(Vector3 rot)\r
-        {\r
-            _rotationAngles = rot;\r
-        }\r
-\r
-        public override void LoadMesh(string filename)\r
-        {\r
-            base.LoadMesh(filename);\r
-\r
-            float minX, minY, minZ;\r
-            minX = minY = minZ = Single.MaxValue;\r
-            float maxX, maxY, maxZ;\r
-            maxX = maxY = maxZ = Single.MinValue;\r
-\r
-            // Generate the vertex array\r
-            RenderData.Vertices = new float[_numVertices * 3];\r
-            int current = 0;\r
-            for (int i = 0; i < _numVertices; i++)\r
-            {\r
-                RenderData.Vertices[current++] = _vertices[i].Coord.X;\r
-                RenderData.Vertices[current++] = _vertices[i].Coord.Y;\r
-                RenderData.Vertices[current++] = _vertices[i].Coord.Z;\r
-\r
-                if (_vertices[i].Coord.X < minX)\r
-                    minX = _vertices[i].Coord.X;\r
-                else if (_vertices[i].Coord.X > maxX)\r
-                    maxX = _vertices[i].Coord.X;\r
-\r
-                if (_vertices[i].Coord.Y < minY)\r
-                    minY = _vertices[i].Coord.Y;\r
-                else if (_vertices[i].Coord.Y > maxY)\r
-                    maxY = _vertices[i].Coord.Y;\r
-\r
-                if (_vertices[i].Coord.Z < minZ)\r
-                    minZ = _vertices[i].Coord.Z;\r
-                else if (_vertices[i].Coord.Z > maxZ)\r
-                    maxZ = _vertices[i].Coord.Z;\r
-            }\r
-\r
-            // Calculate the center-point from the bounding box edges\r
-            RenderData.Center = new Vector3((minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2);\r
-\r
-            // Generate the index array\r
-            RenderData.Indices = new ushort[_numFaces * 3];\r
-            current = 0;\r
-            for (int i = 0; i < _numFaces; i++)\r
-            {\r
-                RenderData.Indices[current++] = (ushort)_faces[i].Indices[0];\r
-                RenderData.Indices[current++] = (ushort)_faces[i].Indices[1];\r
-                RenderData.Indices[current++] = (ushort)_faces[i].Indices[2];\r
-            }\r
-\r
-            // Generate the texcoord array\r
-            RenderData.TexCoords = new float[_numVertices * 2];\r
-            current = 0;\r
-            for (int i = 0; i < _numVertices; i++)\r
-            {\r
-                RenderData.TexCoords[current++] = _vertices[i].TexCoord.X;\r
-                RenderData.TexCoords[current++] = _vertices[i].TexCoord.Y;\r
-            }\r
-        }\r
-\r
-        public override void LoadLODMesh(int level, string filename)\r
-        {\r
-            LODMesh lod = new LODMesh();\r
-            lod.LoadMesh(filename);\r
-            _lodMeshes[level] = lod;\r
-        }\r
-    }\r
-\r
-    public class GLAvatar\r
-    {\r
-        public static Dictionary<string, GLMesh> _meshes = new Dictionary<string, GLMesh>();\r
-        public static bool _wireframe = true;\r
-        public static bool _showSkirt = false;\r
-        public static Dictionary<int, attachment_point> attachment_points = new Dictionary<int, attachment_point>();\r
-\r
-        public static void loadlindenmeshes(string LODfilename)\r
-        {\r
-            Bone.loadbones("avatar_skeleton.xml");\r
-\r
-            string basedir = Directory.GetCurrentDirectory() + System.IO.Path.DirectorySeparatorChar + "character" + System.IO.Path.DirectorySeparatorChar;\r
-\r
-            // Parse through avatar_lad.xml to find all of the mesh references\r
-            XmlDocument lad = new XmlDocument();\r
-            lad.Load(basedir + LODfilename);\r
-\r
-            attachment_points.Clear();\r
-\r
-            XmlNodeList attach_points = lad.GetElementsByTagName("attachment_point");\r
-            foreach (XmlNode apoint in attach_points)\r
-            {\r
-                attachment_point point = new attachment_point();\r
-                point.name = apoint.Attributes.GetNamedItem("name").Value;\r
-                point.joint = apoint.Attributes.GetNamedItem("joint").Value;\r
-\r
-                string pos = apoint.Attributes.GetNamedItem("position").Value;\r
-                string[] posparts = pos.Split(' ');\r
-                point.position = new Vector3(float.Parse(posparts[0]), float.Parse(posparts[1]), float.Parse(posparts[2]));\r
-\r
-                string rot = apoint.Attributes.GetNamedItem("rotation").Value;\r
-                string[] rotparts = rot.Split(' ');\r
-                point.rotation = new Vector3(float.Parse(rotparts[0]), float.Parse(rotparts[1]), float.Parse(rotparts[2]));\r
-\r
-                point.id = Int32.Parse(apoint.Attributes.GetNamedItem("id").Value);\r
-                point.group = Int32.Parse(apoint.Attributes.GetNamedItem("group").Value);\r
-\r
-                attachment_points.Add(point.id, point);\r
-\r
-            }\r
-\r
-            XmlNodeList bones = lad.GetElementsByTagName("bone");\r
-\r
-            XmlNodeList meshes = lad.GetElementsByTagName("mesh");\r
-\r
-            foreach (XmlNode meshNode in meshes)\r
-            {\r
-                string type = meshNode.Attributes.GetNamedItem("type").Value;\r
-                int lod = Int32.Parse(meshNode.Attributes.GetNamedItem("lod").Value);\r
-                string fileName = meshNode.Attributes.GetNamedItem("file_name").Value;\r
-                //string minPixelWidth = meshNode.Attributes.GetNamedItem("min_pixel_width").Value;\r
-\r
-                GLMesh mesh = (_meshes.ContainsKey(type) ? _meshes[type] : new GLMesh(type));\r
-\r
-                switch (mesh.Name)\r
-                {\r
-                    case "lowerBodyMesh":\r
-                        mesh.teFaceID = (int)AvatarTextureIndex.LowerBaked;\r
-                        break;\r
-\r
-                    case "upperBodyMesh":\r
-                        mesh.teFaceID = (int)AvatarTextureIndex.UpperBaked;\r
-                        break;\r
-\r
-                    case "headMesh":\r
-                        mesh.teFaceID = (int)AvatarTextureIndex.HeadBaked;\r
-                        break;\r
-\r
-                    case "hairMesh":\r
-                        mesh.teFaceID = (int)AvatarTextureIndex.HairBaked;\r
-                    break;\r
-\r
-                    case "eyelashMesh":\r
-                        mesh.teFaceID = (int)AvatarTextureIndex.HeadBaked;\r
-                    break;\r
-\r
-                    case "eyeBallRightMesh":\r
-                        mesh.setMeshPos(Bone.getOffset("mEyeLeft"));\r
-                        mesh.setMeshRot(Bone.getRotation("mEyeLeft"));\r
-                        mesh.teFaceID = (int)AvatarTextureIndex.EyesBaked;\r
-                        break;\r
-\r
-                    case "eyeBallLeftMesh":\r
-                        mesh.setMeshPos(Bone.getOffset("mEyeRight"));\r
-                        mesh.setMeshRot(Bone.getRotation("mEyeRight"));\r
-                        mesh.teFaceID = (int)AvatarTextureIndex.EyesBaked;\r
-                        break;\r
-\r
-                    case "skirtMesh":\r
-                        mesh.teFaceID = (int)AvatarTextureIndex.SkirtBaked;\r
-                        break;\r
-\r
-                    default:\r
-                        mesh.teFaceID = 0;\r
-                        break;\r
-                }\r
-\r
-                if (lod == 0)\r
-                {\r
-                    mesh.LoadMesh(basedir + fileName);\r
-                }\r
-                else\r
-                {\r
-                    mesh.LoadLODMesh(lod, basedir + fileName);\r
-                }\r
-\r
-                _meshes[type] = mesh;\r
-\r
-            }\r
-        }\r
-\r
-    }\r
-\r
-    class RenderAvatar\r
-    {\r
-        public GLAvatar glavatar;\r
-        public Avatar avatar;\r
-        public FaceData[] data = new FaceData[32];\r
-\r
-    }\r
-\r
-    public class Bone\r
-    {\r
-        public string name;\r
-        public Vector3 pos;\r
-        public Vector3 rot;\r
-        public Vector3 scale;\r
-        public Vector3 piviot;\r
-\r
-        public Bone parent;\r
-\r
-        public static Dictionary<string, Bone> mBones = new Dictionary<string, Bone>();\r
-\r
-        public static void loadbones(string skeletonfilename)\r
-        {\r
-            mBones.Clear();\r
-            string basedir = Directory.GetCurrentDirectory() + System.IO.Path.DirectorySeparatorChar + "character" + System.IO.Path.DirectorySeparatorChar;\r
-            XmlDocument skeleton = new XmlDocument();\r
-            skeleton.Load(basedir + skeletonfilename);\r
-            XmlNode boneslist = skeleton.GetElementsByTagName("linden_skeleton")[0]; \r
-            addbone(boneslist.ChildNodes[0],null);\r
-        }\r
-\r
-        public static void addbone(XmlNode bone, Bone parent)\r
-        {\r
-            Bone b = new Bone();\r
-            b.name = bone.Attributes.GetNamedItem("name").Value;\r
-\r
-            string pos = bone.Attributes.GetNamedItem("pos").Value;\r
-            string[] posparts = pos.Split(' ');\r
-            b.pos = new Vector3(float.Parse(posparts[0]), float.Parse(posparts[1]), float.Parse(posparts[2]));\r
-\r
-            string rot = bone.Attributes.GetNamedItem("rot").Value;\r
-            string[] rotparts = pos.Split(' ');\r
-            b.pos = new Vector3(float.Parse(rotparts[0]), float.Parse(rotparts[1]), float.Parse(rotparts[2]));\r
-\r
-            string scale = bone.Attributes.GetNamedItem("scale").Value;\r
-            string[] scaleparts = pos.Split(' ');\r
-            b.scale = new Vector3(float.Parse(scaleparts[0]), float.Parse(scaleparts[1]), float.Parse(scaleparts[2]));\r
-\r
-            //TODO piviot\r
-\r
-            b.parent = parent;\r
-\r
-            mBones.Add(b.name, b);\r
-\r
-            Logger.Log("Found bone " + b.name, Helpers.LogLevel.Info);\r
-\r
-            foreach (XmlNode childbone in bone.ChildNodes)\r
-            {\r
-                addbone(childbone,b);\r
-            }\r
-\r
-        }\r
-\r
-        //TODO check offset and rot calcuations should each offset be multiplied by its parent rotation in\r
-        // a standard child/parent rot/offset way?\r
-        public static Vector3 getOffset(string bonename)\r
-        {\r
-            Bone b;\r
-            if (mBones.TryGetValue(bonename, out b))\r
-            {\r
-                return (b.getOffset());\r
-            }\r
-            else\r
-            {\r
-                return Vector3.Zero;\r
-            }\r
-        }\r
-\r
-        public Vector3 getOffset()\r
-        {\r
-            Vector3 totalpos = pos;\r
-\r
-            if (parent != null)\r
-            {\r
-                totalpos = parent.getOffset() + pos;\r
-            }\r
-\r
-            return totalpos;\r
-        }\r
-\r
-        public static Vector3 getRotation(string bonename)\r
-        {\r
-            Bone b;\r
-            if (mBones.TryGetValue(bonename, out b))\r
-            {\r
-                return (b.getRotation());\r
-            }\r
-            else\r
-            {\r
-                return Vector3.Zero;\r
-            }\r
-        }\r
-\r
-        public Vector3 getRotation()\r
-        {\r
-            Vector3 totalrot = rot;\r
-\r
-            if (parent != null)\r
-            {\r
-                totalrot = parent.getRotation() + rot;\r
-            }\r
-\r
-            return totalrot;\r
-        }\r
-    \r
-    }\r
-\r
-}\r
+// 
+// Radegast Metaverse Client
+// Copyright (c) 2009-2014, Radegast Development Team
+// All rights reserved.
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 
+//     * Redistributions of source code must retain the above copyright notice,
+//       this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above copyright
+//       notice, this list of conditions and the following disclaimer in the
+//       documentation and/or other materials provided with the distribution.
+//     * Neither the name of the application "Radegast", nor the names of its
+//       contributors may be used to endorse or promote products derived from
+//       this software without specific prior CreateReflectionTexture permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// $Id: RenderingHelpers.cs 1136 2011-09-05 22:45:11Z latifer $
+//
+
+using System;
+using System.Collections.Generic;
+using System.Collections;
+using System.Linq;
+using System.Text;
+using System.IO;
+using System.IO.Compression;
+using System.Xml;
+using System.Threading;
+using OpenTK.Graphics.OpenGL;
+using System.Runtime.InteropServices;
+using System.Drawing;
+using System.Drawing.Imaging;
+using OpenMetaverse;
+using OpenMetaverse.Rendering;
+
+namespace Radegast.Rendering
+{
+    [StructLayout(LayoutKind.Sequential)]
+    public struct Color4b
+    {
+        public byte R;
+        public byte G;
+        public byte B;
+        public byte A;
+    }
+
+    [StructLayout(LayoutKind.Explicit)]
+    public struct ColorVertex
+    {
+        [FieldOffset(0)]
+        public Vertex Vertex;
+        [FieldOffset(32)]
+        public Color4b Color;
+        public static int Size = 36;
+    }
+
+    public class TextureInfo
+    {
+        public System.Drawing.Image Texture;
+        public int TexturePointer;
+        public bool HasAlpha;
+        public bool FullAlpha;
+        public bool IsMask;
+        public bool IsInvisible;
+        public UUID TextureID;
+        public bool FetchFailed;
+    }
+
+    public class TextureLoadItem
+    {
+        public FaceData Data;
+        public Primitive Prim;
+        public Primitive.TextureEntryFace TeFace;
+        public byte[] TextureData = null;
+        public byte[] TGAData = null;
+        public bool LoadAssetFromCache = false;
+        public OpenMetaverse.ImageType ImageType = OpenMetaverse.ImageType.Normal;
+        public string BakeName = string.Empty;
+        public UUID AvatarID = UUID.Zero;
+    }
+
+    public enum RenderPass
+    {
+        Picking,
+        Simple,
+        Alpha,
+        Invisible
+    }
+
+    public enum SceneObjectType
+    {
+        None,
+        Primitive,
+        Avatar,
+    }
+
+    /// <summary>
+    /// Base class for all scene objects
+    /// </summary>
+    public abstract class SceneObject : IComparable, IDisposable
+    {
+        #region Public fields
+        /// <summary>Interpolated local position of the object</summary>
+        public Vector3 InterpolatedPosition;
+        /// <summary>Interpolated local rotation of the object/summary>
+        public Quaternion InterpolatedRotation;
+        /// <summary>Rendered position of the object in the region</summary>
+        public Vector3 RenderPosition;
+        /// <summary>Rendered rotationm of the object in the region</summary>
+        public Quaternion RenderRotation;
+        /// <summary>Per frame calculated square of the distance from camera</summary>
+        public float DistanceSquared;
+        /// <summary>Bounding volume of the object</summary>
+        public BoundingVolume BoundingVolume;
+        /// <summary>Was the sim position and distance from camera calculated during this frame</summary>
+        public bool PositionCalculated;
+        /// <summary>Scene object type</summary>
+        public SceneObjectType Type = SceneObjectType.None;
+        /// <summary>Libomv primitive</summary>
+        public virtual Primitive BasePrim { get; set; }
+        /// <summary>Were initial initialization tasks done</summary>
+        public bool Initialized;
+        /// <summary>Is this object disposed</summary>
+        public bool IsDisposed = false;
+        public int AlphaQueryID = -1;
+        public int SimpleQueryID = -1;
+        public bool HasAlphaFaces;
+        public bool HasSimpleFaces;
+        public bool HasInvisibleFaces;
+
+        #endregion Public fields
+
+        uint previousParent = uint.MaxValue;
+
+        /// <summary>
+        /// Cleanup resources used
+        /// </summary>
+        public virtual void Dispose()
+        {
+            IsDisposed = true;
+        }
+
+        /// <summary>
+        /// Task performed the fist time object is set for rendering
+        /// </summary>
+        public virtual void Initialize()
+        {
+            RenderPosition = InterpolatedPosition = BasePrim.Position;
+            RenderRotation = InterpolatedRotation = BasePrim.Rotation;
+            Initialized = true;
+        }
+
+        /// <summary>
+        /// Perform per frame tasks
+        /// </summary>
+        /// <param name="time">Time since the last call (last frame time in seconds)</param>
+        public virtual void Step(float time)
+        {
+            if (BasePrim == null) return;
+
+            // Don't interpolate when parent changes (sit/stand link/unlink)
+            if (previousParent != BasePrim.ParentID)
+            {
+                previousParent = BasePrim.ParentID;
+                InterpolatedPosition = BasePrim.Position;
+                InterpolatedRotation = BasePrim.Rotation;
+                return;
+            }
+
+            // Linear velocity and acceleration
+            if (BasePrim.Velocity != Vector3.Zero)
+            {
+                BasePrim.Position = InterpolatedPosition = BasePrim.Position + BasePrim.Velocity * time
+                    * 0.98f * RadegastInstance.GlobalInstance.Client.Network.CurrentSim.Stats.Dilation;
+                BasePrim.Velocity += BasePrim.Acceleration * time;
+            }
+            else if (InterpolatedPosition != BasePrim.Position)
+            {
+                InterpolatedPosition = RHelp.Smoothed1stOrder(InterpolatedPosition, BasePrim.Position, time);
+            }
+
+            // Angular velocity (target omega)
+            if (BasePrim.AngularVelocity != Vector3.Zero)
+            {
+                Vector3 angVel = BasePrim.AngularVelocity;
+                float angle = time * angVel.Length();
+                Quaternion dQ = Quaternion.CreateFromAxisAngle(angVel, angle);
+                InterpolatedRotation = dQ * InterpolatedRotation;
+            }
+            else if (InterpolatedRotation != BasePrim.Rotation && !(this is RenderAvatar))
+            {
+                InterpolatedRotation = Quaternion.Slerp(InterpolatedRotation, BasePrim.Rotation, time * 10f);
+                if (1f - Math.Abs(Quaternion.Dot(InterpolatedRotation, BasePrim.Rotation)) < 0.0001)
+                    InterpolatedRotation = BasePrim.Rotation;
+            }
+            else
+            {
+                InterpolatedRotation = BasePrim.Rotation;
+            }
+        }
+
+        /// <summary>
+        /// Render scene object
+        /// </summary>
+        /// <param name="pass">Which pass are we currently in</param>
+        /// <param name="pickingID">ID used to identify which object was picked</param>
+        /// <param name="scene">Main scene renderer</param>
+        /// <param name="time">Time it took to render the last frame</param>
+        public virtual void Render(RenderPass pass, int pickingID, SceneWindow scene, float time)
+        {
+        }
+
+        /// <summary>
+        /// Implementation of the IComparable interface
+        /// used for sorting by distance
+        /// </summary>
+        /// <param name="other">Object we are comparing to</param>
+        /// <returns>Result of the comparison</returns>
+        public virtual int CompareTo(object other)
+        {
+            SceneObject o = (SceneObject)other;
+            if (this.DistanceSquared < o.DistanceSquared)
+                return -1;
+            else if (this.DistanceSquared > o.DistanceSquared)
+                return 1;
+            else
+                return 0;
+        }
+
+        #region Occlusion queries
+        public void StartQuery(RenderPass pass)
+        {
+            if (!RenderSettings.OcclusionCullingEnabled) return;
+
+            if (pass == RenderPass.Simple)
+            {
+                StartSimpleQuery();
+            }
+            else if (pass == RenderPass.Alpha)
+            {
+                StartAlphaQuery();
+            }
+        }
+
+        public void EndQuery(RenderPass pass)
+        {
+            if (!RenderSettings.OcclusionCullingEnabled) return;
+
+            if (pass == RenderPass.Simple)
+            {
+                EndSimpleQuery();
+            }
+            else if (pass == RenderPass.Alpha)
+            {
+                EndAlphaQuery();
+            }
+        }
+
+        public void StartAlphaQuery()
+        {
+            if (!RenderSettings.OcclusionCullingEnabled) return;
+
+            if (AlphaQueryID == -1)
+            {
+                Compat.GenQueries(out AlphaQueryID);
+            }
+            if (AlphaQueryID > 0)
+            {
+                Compat.BeginQuery(QueryTarget.SamplesPassed, AlphaQueryID);
+            }
+        }
+
+        public void EndAlphaQuery()
+        {
+            if (!RenderSettings.OcclusionCullingEnabled) return;
+
+            if (AlphaQueryID > 0)
+            {
+                Compat.EndQuery(QueryTarget.SamplesPassed);
+            }
+        }
+
+        public void StartSimpleQuery()
+        {
+            if (!RenderSettings.OcclusionCullingEnabled) return;
+
+            if (SimpleQueryID == -1)
+            {
+                Compat.GenQueries(out SimpleQueryID);
+            }
+            if (SimpleQueryID > 0)
+            {
+                Compat.BeginQuery(QueryTarget.SamplesPassed, SimpleQueryID);
+            }
+        }
+
+        public void EndSimpleQuery()
+        {
+            if (!RenderSettings.OcclusionCullingEnabled) return;
+
+            if (SimpleQueryID > 0)
+            {
+                Compat.EndQuery(QueryTarget.SamplesPassed);
+            }
+        }
+
+        public bool Occluded()
+        {
+            if (!RenderSettings.OcclusionCullingEnabled) return false;
+
+            if (HasInvisibleFaces) return false;
+
+            if ((SimpleQueryID == -1 && AlphaQueryID == -1))
+            {
+                return false;
+            }
+
+            if ((!HasAlphaFaces && !HasSimpleFaces)) return true;
+
+            int samples = 1;
+            if (HasSimpleFaces && SimpleQueryID > 0)
+            {
+                Compat.GetQueryObject(SimpleQueryID, GetQueryObjectParam.QueryResult, out samples);
+            }
+            if (HasSimpleFaces && samples > 0)
+            {
+                return false;
+            }
+
+            samples = 1;
+            if (HasAlphaFaces && AlphaQueryID > 0)
+            {
+                Compat.GetQueryObject(AlphaQueryID, GetQueryObjectParam.QueryResult, out samples);
+            }
+            if (HasAlphaFaces && samples > 0)
+            {
+                return false;
+            }
+
+            return true;
+        }
+        #endregion Occlusion queries
+    }
+
+    public static class RHelp
+    {
+        public static readonly Vector3 InvalidPosition = new Vector3(99999f, 99999f, 99999f);
+        static float t1 = 0.075f;
+        static float t2 = t1 / 5.7f;
+
+        public static Vector3 Smoothed1stOrder(Vector3 curPos, Vector3 targetPos, float lastFrameTime)
+        {
+            int numIterations = (int)(lastFrameTime * 100);
+            do
+            {
+                curPos += (targetPos - curPos) * t1;
+                numIterations--;
+            }
+            while (numIterations > 0);
+            if (Vector3.DistanceSquared(curPos, targetPos) < 0.00001f)
+            {
+                curPos = targetPos;
+            }
+            return curPos;
+        }
+
+        public static Vector3 Smoothed2ndOrder(Vector3 curPos, Vector3 targetPos, ref Vector3 accel, float lastFrameTime)
+        {
+            int numIterations = (int)(lastFrameTime * 100);
+            do
+            {
+                accel += (targetPos - accel - curPos) * t1;
+                curPos += accel * t2;
+                numIterations--;
+            }
+            while (numIterations > 0);
+            if (Vector3.DistanceSquared(curPos, targetPos) < 0.00001f)
+            {
+                curPos = targetPos;
+            }
+            return curPos;
+        }
+
+        public static OpenTK.Vector2 TKVector3(Vector2 v)
+        {
+            return new OpenTK.Vector2(v.X, v.Y);
+        }
+
+        public static OpenTK.Vector3 TKVector3(Vector3 v)
+        {
+            return new OpenTK.Vector3(v.X, v.Y, v.Z);
+        }
+
+        public static OpenTK.Vector4 TKVector3(Vector4 v)
+        {
+            return new OpenTK.Vector4(v.X, v.Y, v.Z, v.W);
+        }
+
+        public static Vector2 OMVVector2(OpenTK.Vector2 v)
+        {
+            return new Vector2(v.X, v.Y);
+        }
+
+        public static Vector3 OMVVector3(OpenTK.Vector3 v)
+        {
+            return new Vector3(v.X, v.Y, v.Z);
+        }
+
+        public static Vector4 OMVVector4(OpenTK.Vector4 v)
+        {
+            return new Vector4(v.X, v.Y, v.Z, v.W);
+        }
+
+        public static Color WinColor(OpenTK.Graphics.Color4 color)
+        {
+            return Color.FromArgb((int)(color.A * 255), (int)(color.R * 255), (int)(color.G * 255), (int)(color.B * 255));
+        }
+
+        public static Color WinColor(Color4 color)
+        {
+            return Color.FromArgb((int)(color.A * 255), (int)(color.R * 255), (int)(color.G * 255), (int)(color.B * 255));
+        }
+
+        public static int NextPow2(int start)
+        {
+            int pow = 1;
+            while (pow < start) pow *= 2;
+            return pow;
+        }
+
+        #region Cached image save and load
+        public static readonly string RAD_IMG_MAGIC = "radegast_img";
+
+        public static bool LoadCachedImage(UUID textureID, out byte[] tgaData, out bool hasAlpha, out bool fullAlpha, out bool isMask)
+        {
+            tgaData = null;
+            hasAlpha = fullAlpha = isMask = false;
+
+            try
+            {
+                string fname = RadegastInstance.GlobalInstance.ComputeCacheName(RadegastInstance.GlobalInstance.Client.Settings.ASSET_CACHE_DIR, textureID) + ".rzi";
+
+                using (var f = File.Open(fname, FileMode.Open, FileAccess.Read, FileShare.Read))
+                {
+                    byte[] header = new byte[36];
+                    int i = 0;
+                    f.Read(header, 0, header.Length);
+
+                    // check if the file is starting with magic string
+                    if (RAD_IMG_MAGIC != Utils.BytesToString(header, 0, RAD_IMG_MAGIC.Length))
+                        return false;
+                    i += RAD_IMG_MAGIC.Length;
+
+                    if (header[i++] != 1) // check version
+                        return false;
+
+                    hasAlpha = header[i++] == 1;
+                    fullAlpha = header[i++] == 1;
+                    isMask = header[i++] == 1;
+
+                    int uncompressedSize = Utils.BytesToInt(header, i);
+                    i += 4;
+
+                    textureID = new UUID(header, i);
+                    i += 16;
+
+                    tgaData = new byte[uncompressedSize];
+                    using (var compressed = new DeflateStream(f, CompressionMode.Decompress))
+                    {
+                        int read = 0;
+                        while ((read = compressed.Read(tgaData, read, uncompressedSize - read)) > 0) ;
+                    }
+                }
+
+                return true;
+            }
+            catch (FileNotFoundException) { }
+            catch (Exception ex)
+            {
+                Logger.DebugLog(string.Format("Failed to load radegast cache file {0}: {1}", textureID, ex.Message));
+            }
+            return false;
+        }
+
+        public static bool SaveCachedImage(byte[] tgaData, UUID textureID, bool hasAlpha, bool fullAlpha, bool isMask)
+        {
+            try
+            {
+                string fname = RadegastInstance.GlobalInstance.ComputeCacheName(RadegastInstance.GlobalInstance.Client.Settings.ASSET_CACHE_DIR, textureID) + ".rzi";
+
+                using (var f = File.Open(fname, FileMode.Create, FileAccess.Write, FileShare.None))
+                {
+                    int i = 0;
+                    // magic header
+                    f.Write(Utils.StringToBytes(RAD_IMG_MAGIC), 0, RAD_IMG_MAGIC.Length);
+                    i += RAD_IMG_MAGIC.Length;
+
+                    // version
+                    f.WriteByte((byte)1);
+                    i++;
+
+                    // texture info
+                    f.WriteByte(hasAlpha ? (byte)1 : (byte)0);
+                    f.WriteByte(fullAlpha ? (byte)1 : (byte)0);
+                    f.WriteByte(isMask ? (byte)1 : (byte)0);
+                    i += 3;
+
+                    // texture size
+                    byte[] uncompressedSize = Utils.IntToBytes(tgaData.Length);
+                    f.Write(uncompressedSize, 0, uncompressedSize.Length);
+                    i += uncompressedSize.Length;
+
+                    // texture id
+                    byte[] id = new byte[16];
+                    textureID.ToBytes(id, 0);
+                    f.Write(id, 0, 16);
+                    i += 16;
+
+                    // compressed texture data
+                    using (var compressed = new DeflateStream(f, CompressionMode.Compress))
+                    {
+                        compressed.Write(tgaData, 0, tgaData.Length);
+                    }
+                }
+                return true;
+            }
+            catch (Exception ex)
+            {
+                Logger.DebugLog(string.Format("Failed to save radegast cache file {0}: {1}", textureID, ex.Message));
+                return false;
+            }
+        }
+        #endregion Cached image save and load
+
+        #region Static vertices and indices for a cube (used for bounding box drawing)
+        /**********************************************
+          5 --- 4
+         /|    /|
+        1 --- 0 |
+        | 6 --| 7
+        |/    |/
+        2 --- 3
+        ***********************************************/
+        public static readonly float[] CubeVertices = new float[]
+        {
+             0.5f,  0.5f,  0.5f, // 0
+               -0.5f,  0.5f,  0.5f, // 1
+               -0.5f, -0.5f,  0.5f, // 2
+                0.5f, -0.5f,  0.5f, // 3
+                0.5f,  0.5f, -0.5f, // 4
+               -0.5f,  0.5f, -0.5f, // 5
+               -0.5f, -0.5f, -0.5f, // 6
+                0.5f, -0.5f, -0.5f  // 7
+        };
+
+        public static readonly ushort[] CubeIndices = new ushort[]
+        {
+            0, 1, 2, 3,     // Front Face
+               4, 5, 6, 7,     // Back Face
+               1, 2, 6, 5,     // Left Face
+               0, 3, 7, 4,     // Right Face
+               0, 1, 5, 4,     // Top Face
+               2, 3, 7, 6      // Bottom Face
+        };
+        #endregion Static vertices and indices for a cube (used for bounding box drawing)
+
+        public static int GLLoadImage(Bitmap bitmap, bool hasAlpha)
+        {
+            return GLLoadImage(bitmap, hasAlpha, true);
+        }
+
+        public static int GLLoadImage(Bitmap bitmap, bool hasAlpha, bool useMipmap)
+        {
+            useMipmap = useMipmap && RenderSettings.HasMipmap;
+            int ret = -1;
+            GL.GenTextures(1, out ret);
+            GL.BindTexture(TextureTarget.Texture2D, ret);
+
+            Rectangle rectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
+
+            BitmapData bitmapData =
+                bitmap.LockBits(
+                rectangle,
+                ImageLockMode.ReadOnly,
+                hasAlpha ? System.Drawing.Imaging.PixelFormat.Format32bppArgb : System.Drawing.Imaging.PixelFormat.Format24bppRgb);
+
+            GL.TexImage2D(
+                TextureTarget.Texture2D,
+                0,
+                hasAlpha ? PixelInternalFormat.Rgba : PixelInternalFormat.Rgb8,
+                bitmap.Width,
+                bitmap.Height,
+                0,
+                hasAlpha ? OpenTK.Graphics.OpenGL.PixelFormat.Bgra : OpenTK.Graphics.OpenGL.PixelFormat.Bgr,
+                PixelType.UnsignedByte,
+                bitmapData.Scan0);
+
+            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
+            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
+            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
+            if (useMipmap)
+            {
+                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);
+                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.GenerateMipmap, 1);
+                GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
+            }
+            else
+            {
+                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
+            }
+
+            bitmap.UnlockBits(bitmapData);
+            return ret;
+        }
+
+        public static void Draw2DBox(float x, float y, float width, float height, float depth)
+        {
+            GL.Begin(BeginMode.Quads);
+            {
+                GL.TexCoord2(0, 1);
+                GL.Vertex3(x, y, depth);
+                GL.TexCoord2(1, 1);
+                GL.Vertex3(x + width, y, depth);
+                GL.TexCoord2(1, 0);
+                GL.Vertex3(x + width, y + height, depth);
+                GL.TexCoord2(0, 0);
+                GL.Vertex3(x, y + height, depth);
+            }
+            GL.End();
+        }
+
+        public static void ResetMaterial()
+        {
+            GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Ambient, new float[] { 0.2f, 0.2f, 0.2f, 1.0f });
+            GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Diffuse, new float[] { 0.8f, 0.8f, 0.8f, 1.0f });
+            GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Specular, new float[] { 0f, 0f, 0f, 1.0f });
+            GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Emission, new float[] { 0f, 0f, 0f, 1.0f });
+            GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Shininess, 0f);
+            ShaderProgram.Stop();
+        }
+    }
+
+    /// <summary>
+    /// Represents camera object
+    /// </summary>
+    public class Camera
+    {
+        /// <summary>
+        /// Indicates that there was manual camera movement, stop tracking objects
+        /// </summary>
+        public bool Manual;
+        Vector3 mPosition;
+        Vector3 mFocalPoint;
+        bool mModified;
+
+        /// <summary>Camera position</summary>
+        public Vector3 Position
+        {
+            get
+            {
+                return mPosition;
+            }
+            
+            set
+            {
+                if (mPosition != value)
+                {
+                    mPosition = value;
+                    Modify();
+                }
+            }
+        }
+
+        /// <summary>Camera target</summary>
+        public Vector3 FocalPoint
+        {
+            get
+            {
+                return mFocalPoint;
+            }
+            
+            set
+            {
+                if (mFocalPoint != value)
+                {
+                    mFocalPoint = value;
+                    Modify();
+                }
+            }
+        }
+
+        /// <summary>Zoom level</summary>
+        public float Zoom;
+        /// <summary>Draw distance</summary>
+        public float Far;
+        /// <summary>Has camera been modified</summary>
+        public bool Modified { get { return mModified; } set { mModified = value; } }
+
+        public float TimeToTarget = 0f;
+
+        public Vector3 RenderPosition;
+        public Vector3 RenderFocalPoint;
+
+        void Modify()
+        {
+            mModified = true;
+        }
+
+        public void Step(float time)
+        {
+            if (RenderPosition != Position)
+            {
+                RenderPosition = RHelp.Smoothed1stOrder(RenderPosition, Position, time);
+                Modified = true;
+            }
+            if (RenderFocalPoint != FocalPoint)
+            {
+                RenderFocalPoint = RHelp.Smoothed1stOrder(RenderFocalPoint, FocalPoint, time);
+                Modified = true;
+            }
+        }
+
+#if OBSOLETE_CODE
+        [Obsolete("Use Step(), left in here for reference")]
+        public void Step2(float time)
+        {
+            TimeToTarget -= time;
+            if (TimeToTarget <= time)
+            {
+                EndMove();
+                return;
+            }
+
+            mModified = true;
+
+            float pctElapsed = time / TimeToTarget;
+
+            if (RenderPosition != Position)
+            {
+                float distance = Vector3.Distance(RenderPosition, Position);
+                RenderPosition = Vector3.Lerp(RenderPosition, Position, distance * pctElapsed);
+            }
+
+            if (RenderFocalPoint != FocalPoint)
+            {
+                RenderFocalPoint = Interpolate(RenderFocalPoint, FocalPoint, pctElapsed);
+            }
+        }
+
+        Vector3 Interpolate(Vector3 start, Vector3 end, float fraction)
+        {
+            float distance = Vector3.Distance(start, end);
+            Vector3 direction = end - start;
+            return start + direction * fraction;
+        }
+
+        public void EndMove()
+        {
+            mModified = true;
+            TimeToTarget = 0;
+            RenderPosition = Position;
+            RenderFocalPoint = FocalPoint;
+        }
+#endif
+
+        public void Pan(float deltaX, float deltaY)
+        {
+            Manual = true;
+            Vector3 direction = Position - FocalPoint;
+            direction.Normalize();
+            Vector3 vy = direction % Vector3.UnitZ;
+            Vector3 vx = vy % direction;
+            Vector3 vxy = vx * deltaY + vy * deltaX;
+            Position += vxy;
+            FocalPoint += vxy;
+        }
+
+        public void Rotate(float delta, bool horizontal)
+        {
+            Manual = true;
+            Vector3 direction = Position - FocalPoint;
+            if (horizontal)
+            {
+                Position = FocalPoint + direction * new Quaternion(0f, 0f, (float)Math.Sin(delta), (float)Math.Cos(delta));
+            }
+            else
+            {
+                Position = FocalPoint + direction * Quaternion.CreateFromAxisAngle(direction % Vector3.UnitZ, delta);
+            }
+        }
+
+        public void MoveToTarget(float delta)
+        {
+            Manual = true;
+            Position += (Position - FocalPoint) * delta;
+        }
+
+        /// <summary>
+        /// Sets the world in perspective of the camera
+        /// </summary>
+        public void LookAt()
+        {
+            OpenTK.Matrix4 lookAt = OpenTK.Matrix4.LookAt(
+                RenderPosition.X, RenderPosition.Y, RenderPosition.Z,
+                RenderFocalPoint.X, RenderFocalPoint.Y, RenderFocalPoint.Z,
+                0f, 0f, 1f);
+            GL.MultMatrix(ref lookAt);
+        }
+    }
+
+    public static class MeshToOBJ
+    {
+        public static bool MeshesToOBJ(Dictionary<uint, FacetedMesh> meshes, string filename)
+        {
+            StringBuilder obj = new StringBuilder();
+            StringBuilder mtl = new StringBuilder();
+
+            FileInfo objFileInfo = new FileInfo(filename);
+
+            string mtlFilename = objFileInfo.FullName.Substring(objFileInfo.DirectoryName.Length + 1,
+                objFileInfo.FullName.Length - (objFileInfo.DirectoryName.Length + 1) - 4) + ".mtl";
+
+            obj.AppendLine("# Created by libprimrender");
+            obj.AppendLine("mtllib ./" + mtlFilename);
+            obj.AppendLine();
+
+            mtl.AppendLine("# Created by libprimrender");
+            mtl.AppendLine();
+
+            int primNr = 0;
+            foreach (FacetedMesh mesh in meshes.Values)
+            {
+                for (int j = 0; j < mesh.Faces.Count; j++)
+                {
+                    Face face = mesh.Faces[j];
+
+                    if (face.Vertices.Count > 2)
+                    {
+                        string mtlName = String.Format("material{0}-{1}", primNr, face.ID);
+                        Primitive.TextureEntryFace tex = face.TextureFace;
+                        string texName = tex.TextureID.ToString() + ".tga";
+
+                        // FIXME: Convert the source to TGA (if needed) and copy to the destination
+
+                        float shiny = 0.00f;
+                        switch (tex.Shiny)
+                        {
+                            case Shininess.High:
+                                shiny = 1.00f;
+                                break;
+                            case Shininess.Medium:
+                                shiny = 0.66f;
+                                break;
+                            case Shininess.Low:
+                                shiny = 0.33f;
+                                break;
+                        }
+
+                        obj.AppendFormat("g face{0}-{1}{2}", primNr, face.ID, Environment.NewLine);
+
+                        mtl.AppendLine("newmtl " + mtlName);
+                        mtl.AppendFormat("Ka {0} {1} {2}{3}", tex.RGBA.R, tex.RGBA.G, tex.RGBA.B, Environment.NewLine);
+                        mtl.AppendFormat("Kd {0} {1} {2}{3}", tex.RGBA.R, tex.RGBA.G, tex.RGBA.B, Environment.NewLine);
+                        //mtl.AppendFormat("Ks {0} {1} {2}{3}");
+                        mtl.AppendLine("Tr " + tex.RGBA.A);
+                        mtl.AppendLine("Ns " + shiny);
+                        mtl.AppendLine("illum 1");
+                        if (tex.TextureID != UUID.Zero && tex.TextureID != Primitive.TextureEntry.WHITE_TEXTURE)
+                            mtl.AppendLine("map_Kd ./" + texName);
+                        mtl.AppendLine();
+
+                        // Write the vertices, texture coordinates, and vertex normals for this side
+                        for (int k = 0; k < face.Vertices.Count; k++)
+                        {
+                            Vertex vertex = face.Vertices[k];
+
+                            #region Vertex
+
+                            Vector3 pos = vertex.Position;
+
+                            // Apply scaling
+                            pos *= mesh.Prim.Scale;
+
+                            // Apply rotation
+                            pos *= mesh.Prim.Rotation;
+
+                            // The root prim position is sim-relative, while child prim positions are
+                            // parent-relative. We want to apply parent-relative translations but not
+                            // sim-relative ones
+                            if (mesh.Prim.ParentID != 0)
+                                pos += mesh.Prim.Position;
+
+                            obj.AppendFormat("v {0} {1} {2}{3}", pos.X, pos.Y, pos.Z, Environment.NewLine);
+
+                            #endregion Vertex
+
+                            #region Texture Coord
+
+                            obj.AppendFormat("vt {0} {1}{2}", vertex.TexCoord.X, vertex.TexCoord.Y,
+                                Environment.NewLine);
+
+                            #endregion Texture Coord
+
+                            #region Vertex Normal
+
+                            // HACK: Sometimes normals are getting set to <NaN,NaN,NaN>
+                            if (!Single.IsNaN(vertex.Normal.X) && !Single.IsNaN(vertex.Normal.Y) && !Single.IsNaN(vertex.Normal.Z))
+                                obj.AppendFormat("vn {0} {1} {2}{3}", vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z,
+                                    Environment.NewLine);
+                            else
+                                obj.AppendLine("vn 0.0 1.0 0.0");
+
+                            #endregion Vertex Normal
+                        }
+
+                        obj.AppendFormat("# {0} vertices{1}", face.Vertices.Count, Environment.NewLine);
+                        obj.AppendLine();
+                        obj.AppendLine("usemtl " + mtlName);
+
+                        #region Elements
+
+                        // Write all of the faces (triangles) for this side
+                        for (int k = 0; k < face.Indices.Count / 3; k++)
+                        {
+                            obj.AppendFormat("f -{0}/-{0}/-{0} -{1}/-{1}/-{1} -{2}/-{2}/-{2}{3}",
+                                face.Vertices.Count - face.Indices[k * 3 + 0],
+                                face.Vertices.Count - face.Indices[k * 3 + 1],
+                                face.Vertices.Count - face.Indices[k * 3 + 2],
+                                Environment.NewLine);
+                        }
+
+                        obj.AppendFormat("# {0} elements{1}", face.Indices.Count / 3, Environment.NewLine);
+                        obj.AppendLine();
+
+                        #endregion Elements
+                    }
+                }
+                primNr++;
+            }
+
+            try
+            {
+                File.WriteAllText(filename, obj.ToString());
+                File.WriteAllText(mtlFilename, mtl.ToString());
+            }
+            catch (Exception)
+            {
+                return false;
+            }
+
+            return true;
+        }
+    }
+
+    public static class Math3D
+    {
+        // Column-major:
+        // |  0  4  8 12 |
+        // |  1  5  9 13 |
+        // |  2  6 10 14 |
+        // |  3  7 11 15 |
+
+        public static float[] CreateTranslationMatrix(Vector3 v)
+        {
+            float[] mat = new float[16];
+
+            mat[12] = v.X;
+            mat[13] = v.Y;
+            mat[14] = v.Z;
+            mat[0] = mat[5] = mat[10] = mat[15] = 1;
+
+            return mat;
+        }
+
+        public static float[] CreateRotationMatrix(Quaternion q)
+        {
+            float[] mat = new float[16];
+
+            // Transpose the quaternion (don't ask me why)
+            q.X = q.X * -1f;
+            q.Y = q.Y * -1f;
+            q.Z = q.Z * -1f;
+
+            float x2 = q.X + q.X;
+            float y2 = q.Y + q.Y;
+            float z2 = q.Z + q.Z;
+            float xx = q.X * x2;
+            float xy = q.X * y2;
+            float xz = q.X * z2;
+            float yy = q.Y * y2;
+            float yz = q.Y * z2;
+            float zz = q.Z * z2;
+            float wx = q.W * x2;
+            float wy = q.W * y2;
+            float wz = q.W * z2;
+
+            mat[0] = 1.0f - (yy + zz);
+            mat[1] = xy - wz;
+            mat[2] = xz + wy;
+            mat[3] = 0.0f;
+
+            mat[4] = xy + wz;
+            mat[5] = 1.0f - (xx + zz);
+            mat[6] = yz - wx;
+            mat[7] = 0.0f;
+
+            mat[8] = xz - wy;
+            mat[9] = yz + wx;
+            mat[10] = 1.0f - (xx + yy);
+            mat[11] = 0.0f;
+
+            mat[12] = 0.0f;
+            mat[13] = 0.0f;
+            mat[14] = 0.0f;
+            mat[15] = 1.0f;
+
+            return mat;
+        }
+
+        public static float[] CreateSRTMatrix(Vector3 scale, Quaternion q, Vector3 pos)
+        {
+            float[] mat = new float[16];
+
+            // Transpose the quaternion (don't ask me why)
+            q.X = q.X * -1f;
+            q.Y = q.Y * -1f;
+            q.Z = q.Z * -1f;
+
+            float x2 = q.X + q.X;
+            float y2 = q.Y + q.Y;
+            float z2 = q.Z + q.Z;
+            float xx = q.X * x2;
+            float xy = q.X * y2;
+            float xz = q.X * z2;
+            float yy = q.Y * y2;
+            float yz = q.Y * z2;
+            float zz = q.Z * z2;
+            float wx = q.W * x2;
+            float wy = q.W * y2;
+            float wz = q.W * z2;
+
+            mat[0] = (1.0f - (yy + zz)) * scale.X;
+            mat[1] = (xy - wz) * scale.X;
+            mat[2] = (xz + wy) * scale.X;
+            mat[3] = 0.0f;
+
+            mat[4] = (xy + wz) * scale.Y;
+            mat[5] = (1.0f - (xx + zz)) * scale.Y;
+            mat[6] = (yz - wx) * scale.Y;
+            mat[7] = 0.0f;
+
+            mat[8] = (xz - wy) * scale.Z;
+            mat[9] = (yz + wx) * scale.Z;
+            mat[10] = (1.0f - (xx + yy)) * scale.Z;
+            mat[11] = 0.0f;
+
+            //Positional parts
+            mat[12] = pos.X;
+            mat[13] = pos.Y;
+            mat[14] = pos.Z;
+            mat[15] = 1.0f;
+
+            return mat;
+        }
+
+
+        public static float[] CreateScaleMatrix(Vector3 v)
+        {
+            float[] mat = new float[16];
+
+            mat[0] = v.X;
+            mat[5] = v.Y;
+            mat[10] = v.Z;
+            mat[15] = 1;
+
+            return mat;
+        }
+
+        public static float[] Lerp(float[] matrix1, float[] matrix2, float amount)
+        {
+
+            float[] lerp = new float[16];
+            //Probably not doing this as a loop is cheaper(unrolling)
+            //also for performance we probably should not create new objects
+            // but meh.
+            for (int x = 0; x < 16; x++)
+            {
+                lerp[x] = matrix1[x] + ((matrix2[x] - matrix1[x]) * amount);
+            }
+
+            return lerp;
+        }
+
+
+        public static bool GluProject(OpenTK.Vector3 objPos, OpenTK.Matrix4 modelMatrix, OpenTK.Matrix4 projMatrix, int[] viewport, out OpenTK.Vector3 screenPos)
+        {
+            OpenTK.Vector4 _in;
+            OpenTK.Vector4 _out;
+
+            _in.X = objPos.X;
+            _in.Y = objPos.Y;
+            _in.Z = objPos.Z;
+            _in.W = 1.0f;
+
+            _out = OpenTK.Vector4.Transform(_in, modelMatrix);
+            _in = OpenTK.Vector4.Transform(_out, projMatrix);
+
+            if (_in.W <= 0.0)
+            {
+                screenPos = OpenTK.Vector3.Zero;
+                return false;
+            }
+
+            _in.X /= _in.W;
+            _in.Y /= _in.W;
+            _in.Z /= _in.W;
+            /* Map x, y and z to range 0-1 */
+            _in.X = _in.X * 0.5f + 0.5f;
+            _in.Y = _in.Y * 0.5f + 0.5f;
+            _in.Z = _in.Z * 0.5f + 0.5f;
+
+            /* Map x,y to viewport */
+            _in.X = _in.X * viewport[2] + viewport[0];
+            _in.Y = _in.Y * viewport[3] + viewport[1];
+
+            screenPos.X = _in.X;
+            screenPos.Y = _in.Y;
+            screenPos.Z = _in.Z;
+
+            return true;
+        }
+
+        public static bool GluUnProject(float winx, float winy, float winz, OpenTK.Matrix4 modelMatrix, OpenTK.Matrix4 projMatrix, int[] viewport, out OpenTK.Vector3 pos)
+        {
+            OpenTK.Matrix4 finalMatrix;
+            OpenTK.Vector4 _in;
+            OpenTK.Vector4 _out;
+
+            finalMatrix = OpenTK.Matrix4.Mult(modelMatrix, projMatrix);
+
+            finalMatrix.Invert();
+
+            _in.X = winx;
+            _in.Y = winy;
+            _in.Z = winz;
+            _in.W = 1.0f;
+
+            /* Map x and y from window coordinates */
+            _in.X = (_in.X - viewport[0]) / viewport[2];
+            _in.Y = (_in.Y - viewport[1]) / viewport[3];
+
+            pos = OpenTK.Vector3.Zero;
+
+            /* Map to range -1 to 1 */
+            _in.X = _in.X * 2 - 1;
+            _in.Y = _in.Y * 2 - 1;
+            _in.Z = _in.Z * 2 - 1;
+
+            //__gluMultMatrixVecd(finalMatrix, _in, _out);
+            // check if this works:
+            _out = OpenTK.Vector4.Transform(_in, finalMatrix);
+
+            if (_out.W == 0.0f)
+                return false;
+            _out.X /= _out.W;
+            _out.Y /= _out.W;
+            _out.Z /= _out.W;
+            pos.X = _out.X;
+            pos.Y = _out.Y;
+            pos.Z = _out.Z;
+            return true;
+        }
+
+        public static double[] AbovePlane(double height)
+        {
+            return new double[] { 0, 0, 1, -height };
+        }
+
+        public static double[] BelowPlane(double height)
+        {
+            return new double[] { 0, 0, -1, height };
+        }
+    }
+
+    /*
+     *  Helper classs for reading the static VFS file, call 
+     *  staticVFS.readVFSheaders() with the path to the static_data.db2 and static_index.db2 files
+     *  and it will pass and dump in to openmetaverse_data for you
+     *  This should only be needed to be used if LL update the static VFS in order to refresh our data
+     */
+
+    class VFSblock
+    {
+        public int mLocation;
+        public int mLength;
+        public int mAccessTime;
+        public UUID mFileID;
+        public int mSize;
+        public AssetType mAssetType;
+
+        public int readblock(byte[] blockdata, int offset)
+        {
+
+            BitPack input = new BitPack(blockdata, offset);
+            mLocation = input.UnpackInt();
+            mLength = input.UnpackInt();
+            mAccessTime = input.UnpackInt();
+            mFileID = input.UnpackUUID();
+            int filetype = input.UnpackShort();
+            mAssetType = (AssetType)filetype;
+            mSize = input.UnpackInt();
+            offset += 34;
+
+            Logger.Log(String.Format("Found header for {0} type {1} length {2} at {3}", mFileID, mAssetType, mSize, mLocation), Helpers.LogLevel.Info);
+
+            return offset;
+        }
+
+    }
+
+    public class staticVFS
+    {
+        public static void readVFSheaders(string datafile, string indexfile)
+        {
+            FileStream datastream;
+            FileStream indexstream;
+
+            datastream = File.Open(datafile, FileMode.Open);
+            indexstream = File.Open(indexfile, FileMode.Open);
+
+            int offset = 0;
+
+            byte[] blockdata = new byte[indexstream.Length];
+            indexstream.Read(blockdata, 0, (int)indexstream.Length);
+
+            while (offset < indexstream.Length)
+            {
+                VFSblock block = new VFSblock();
+                offset = block.readblock(blockdata, offset);
+
+                FileStream writer = File.Open(OpenMetaverse.Settings.RESOURCE_DIR + System.IO.Path.DirectorySeparatorChar + block.mFileID.ToString(), FileMode.Create);
+                byte[] data = new byte[block.mSize];
+                datastream.Seek(block.mLocation, SeekOrigin.Begin);
+                datastream.Read(data, 0, block.mSize);
+                writer.Write(data, 0, block.mSize);
+                writer.Close();
+            }
+
+        }
+    }
+}
\ No newline at end of file