Exemple #1
0
        // Add the submesh to the passed FacetedMesh as a new face.
        private void AddSubMesh(OMV.Primitive prim, int faceIndex, OSD subMeshOsd, ref OMVR.FacetedMesh holdingMesh)
        {
            if (subMeshOsd is OSDMap subMesh)
            {
                // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level
                // of Detail Blocks (maps) contain just a NoGeometry key to signal there is no
                // geometry for this submesh.
                if (subMesh.ContainsKey("NoGeometry") && ((OSDBoolean)subMesh["NoGeometry"]))
                {
                    return;
                }

                Face oface = new Face
                {
                    ID          = faceIndex,
                    Vertices    = new List <Vertex>(),
                    Indices     = new List <ushort>(),
                    TextureFace = prim.Textures.GetFace((uint)faceIndex)
                };

                OSDMap subMeshMap = subMesh;

                oface.Vertices = CollectVertices(subMeshMap);
                oface.Indices  = CollectIndices(subMeshMap);

                holdingMesh.Faces.Add(oface);
            }
        }
        /// <summary>
        /// Create a faceted mesh from prim shape parameters.
        /// Generates a a series of faces, each face containing a mesh and
        /// material metadata.
        /// A prim will turn into multiple faces with each being independent
        /// meshes and each having different material information.
        /// </summary>
        /// <param name="prim">Primitive to generate the mesh from</param>
        /// <param name="lod">Level of detail to generate the mesh at</param>
        /// <returns>The generated mesh</returns >
        public OMVR.FacetedMesh GenerateFacetedMesh(OMV.Primitive prim, OMVR.DetailLevel lod)
        {
            bool isSphere = ((OMV.ProfileCurve)(prim.PrimData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle);

            PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, true);
            if (newPrim == null)
            {
                return(null);
            }

            // copy the vertex information into OMVR.IRendering structures
            OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
            omvrmesh.Faces             = new List <OMVR.Face>();
            omvrmesh.Prim              = prim;
            omvrmesh.Profile           = new OMVR.Profile();
            omvrmesh.Profile.Faces     = new List <OMVR.ProfileFace>();
            omvrmesh.Profile.Positions = new List <OMV.Vector3>();
            omvrmesh.Path              = new OMVR.Path();
            omvrmesh.Path.Points       = new List <OMVR.PathPoint>();
            var indexer = newPrim.GetVertexIndexer();

            for (int i = 0; i < indexer.numPrimFaces; i++)
            {
                OMVR.Face oface = new OMVR.Face();
                oface.Vertices    = new List <OMVR.Vertex>();
                oface.Indices     = new List <ushort>();
                oface.TextureFace = prim.Textures.GetFace((uint)i);

                for (int j = 0; j < indexer.viewerVertices[i].Count; j++)
                {
                    var vert = new OMVR.Vertex();
                    var m    = indexer.viewerVertices[i][j];
                    vert.Position = new Vector3(m.v.X, m.v.Y, m.v.Z);
                    vert.Normal   = new Vector3(m.n.X, m.n.Y, m.n.Z);
                    vert.TexCoord = new OMV.Vector2(m.uv.U, 1.0f - m.uv.V);
                    oface.Vertices.Add(vert);
                }

                for (int j = 0; j < indexer.viewerPolygons[i].Count; j++)
                {
                    var p = indexer.viewerPolygons[i][j];
                    // Skip "degenerate faces" where the same vertex appears twice in the same tri
                    if (p.v1 == p.v2 || p.v1 == p.v2 || p.v2 == p.v3)
                    {
                        continue;
                    }
                    oface.Indices.Add((ushort)p.v1);
                    oface.Indices.Add((ushort)p.v2);
                    oface.Indices.Add((ushort)p.v3);
                }

                omvrmesh.Faces.Add(oface);
            }

            return(omvrmesh);
        }
        public FacetedMesh GenerateFacetedMesh(Primitive prim, DetailLevel lod)
        {
            Path path = GeneratePath();
            Profile profile = GenerateProfile();

            FacetedMesh mesh = new FacetedMesh();
            mesh.Prim = prim;
            mesh.Path = path;
            mesh.Profile = profile;
            mesh.Faces = GenerateFaces(prim.Textures);

            return mesh;
        }
Exemple #4
0
 private Promise <DisplayableRenderable> MeshFromPrimShapeData(SceneObjectGroup sog, SceneObjectPart sop,
                                                               OMV.Primitive prim, IAssetFetcher assetFetcher, OMVR.DetailLevel lod)
 {
     return(new Promise <DisplayableRenderable>((resolve, reject) => {
         OMVR.FacetedMesh mesh = _mesher.GenerateFacetedMesh(prim, lod);
         DisplayableRenderable dr = ConvertFacetedMeshToDisplayable(assetFetcher, mesh, prim.Textures.DefaultTexture, prim.Scale);
         BHash drHash = dr.GetBHash();
         DisplayableRenderable realDR = assetFetcher.GetRenderable(drHash, () => { return dr; });
         BConverterOS.LogBProgress("{0} MeshFromPrimShapeData. numGenedMeshed={1}",
                                   _logHeader, ((RenderableMeshGroup)realDR).meshes.Count);
         resolve(realDR);
     }));
 }
Exemple #5
0
        public FacetedMesh GenerateFacetedMesh(Primitive prim, DetailLevel lod)
        {
            Path    path    = GeneratePath();
            Profile profile = GenerateProfile();

            FacetedMesh mesh = new FacetedMesh();

            mesh.Prim    = prim;
            mesh.Path    = path;
            mesh.Profile = profile;
            mesh.Faces   = GenerateFaces(prim.Textures);

            return(mesh);
        }
Exemple #6
0
        public FacetedMesh GenerateFacetedMesh(Primitive prim, DetailLevel lod)
        {
            float detail = DETAIL_LEVELS[(int)lod];

            Path path = GeneratePath(prim.Data, detail);
            Profile profile = GenerateProfile(prim.Data, path, detail);

            List<Vertex> vertices = GenerateVertices(prim.Data, detail, path, profile);

            FacetedMesh mesh = new FacetedMesh();
            mesh.Prim = prim;
            mesh.Path = path;
            mesh.Profile = profile;
            mesh.Faces = CreateVolumeFaces(prim, path, profile, vertices);

            return mesh;
        }
Exemple #7
0
        // Convert a compressed submesh buffer into a FacetedMesh.
        public FacetedMesh MeshSubMeshAsFacetedMesh(OMV.Primitive prim, byte[] compressedMeshData)
        {
            FacetedMesh ret     = null;
            OSD         meshOSD = Helpers.DecompressOSD(compressedMeshData);

            OSDArray meshFaces = meshOSD as OSDArray;

            if (meshFaces != null)
            {
                ret = new FacetedMesh {
                    Faces = new List <Face>()
                };
                for (int faceIndex = 0; faceIndex < meshFaces.Count; faceIndex++)
                {
                    AddSubMesh(prim, faceIndex, meshFaces[faceIndex], ref ret);
                }
            }
            return(ret);
        }
        /// <summary>
        /// Generates a sculpt mesh structure from a primitive
        /// </summary>
        /// <param name="prim">Primitive to generate the mesh from</param>
        /// <param name="lod">Level of detail to generate the mesh at</param>
        /// <returns>The generated mesh</returns>
        public OMVR.SimpleMesh GenerateSimpleSculptMesh(OMV.Primitive prim, Bitmap bits, OMVR.DetailLevel lod)
        {
            OMVR.FacetedMesh faceted = GenerateFacetedSculptMesh(prim, bits, lod);

            if (faceted != null && faceted.Faces.Count == 1)
            {
                OMVR.Face face = faceted.Faces[0];

                OMVR.SimpleMesh mesh = new OMVR.SimpleMesh();
                mesh.Indices  = face.Indices;
                mesh.Vertices = face.Vertices;
                mesh.Path     = faceted.Path;
                mesh.Prim     = prim;
                mesh.Profile  = faceted.Profile;
                mesh.Vertices = face.Vertices;

                return(mesh);
            }
            return(null);
        }
Exemple #9
0
 private Promise <DisplayableRenderable> MeshFromPrimSculptData(SceneObjectGroup sog, SceneObjectPart sop,
                                                                OMV.Primitive prim, IAssetFetcher assetFetcher, OMVR.DetailLevel lod)
 {
     return(new Promise <DisplayableRenderable>((resolve, reject) => {
         // Get the asset that the sculpty is built on
         EntityHandleUUID texHandle = new EntityHandleUUID(prim.Sculpt.SculptTexture);
         assetFetcher.FetchTexture(texHandle)
         .Then((bm) => {
             OMVR.FacetedMesh fMesh = _mesher.GenerateFacetedSculptMesh(prim, bm.Image.ExportBitmap(), lod);
             DisplayableRenderable dr =
                 ConvertFacetedMeshToDisplayable(assetFetcher, fMesh, prim.Textures.DefaultTexture, prim.Scale);
             BHash drHash = dr.GetBHash();
             DisplayableRenderable realDR = assetFetcher.GetRenderable(drHash, () => { return dr; });
             BConverterOS.LogBProgress("{0} MeshFromPrimSculptData. numFaces={1}, numGenedMeshed={2}",
                                       _logHeader, fMesh.Faces.Count, ((RenderableMeshGroup)realDR).meshes.Count);
             resolve(realDR);
         }, (e) => {
             ConvOAR.Globals.log.ErrorFormat("{0} MeshFromPrimSculptData: Rejected FetchTexture: {1}: {2}", _logHeader, texHandle, e);
             reject(null);
         });
     }));
 }
Exemple #10
0
        private Promise <DisplayableRenderable> MeshFromPrimMeshData(SceneObjectGroup sog, SceneObjectPart sop,
                                                                     OMV.Primitive prim, IAssetFetcher assetFetcher, OMVR.DetailLevel lod)
        {
            EntityHandleUUID meshHandle = new EntityHandleUUID(prim.Sculpt.SculptTexture);

            return(new Promise <DisplayableRenderable>((resolve, reject) => {
                assetFetcher.FetchRawAsset(meshHandle)
                .Then(meshBytes => {
                    // OMVA.AssetMesh meshAsset = new OMVA.AssetMesh(prim.ID, meshBytes);
                    // if (OMVR.FacetedMesh.TryDecodeFromAsset(prim, meshAsset, lod, out fMesh)) {
                    OMVR.FacetedMesh fMesh = null;
                    try {
                        fMesh = _mesher.GenerateFacetedMeshMesh(prim, meshBytes);
                    }
                    catch (Exception e) {
                        ConvOAR.Globals.log.ErrorFormat("{0} Exception in GenerateFacetedMeshMesh: {1}", _logHeader, e);
                    }
                    if (fMesh != null)
                    {
                        DisplayableRenderable dr = ConvertFacetedMeshToDisplayable(assetFetcher, fMesh, prim.Textures.DefaultTexture, prim.Scale);
                        // Don't know the hash of the DisplayableRenderable until after it has been created.
                        // Now use the hash to see if this has already been done.
                        // If this DisplayableRenderable has already been built, use the other one and throw this away.
                        BHash drHash = dr.GetBHash();
                        DisplayableRenderable realDR = assetFetcher.GetRenderable(drHash, () => { return dr; });
                        resolve(realDR);
                    }
                    else
                    {
                        reject(new Exception("MeshFromPrimMeshData: could not decode mesh information from asset. ID="
                                             + prim.ID.ToString()));
                    }
                }, e => {
                    ConvOAR.Globals.log.ErrorFormat("{0} MeshFromPrimMeshData: exception: {1}", _logHeader, e);
                    reject(e);
                });
            }));
        }
Exemple #11
0
        // A version of GenerateFacetedMeshMesh that takes LOD spec so it's similar in calling convention of
        //    the other Generate* methods.
        public OMVR.FacetedMesh GenerateFacetedMeshMesh(OMV.Primitive prim, byte[] meshData, OMVR.DetailLevel lod)
        {
            OMVR.FacetedMesh ret      = null;
            string           partName = null;

            switch (lod)
            {
            case OMVR.DetailLevel.Highest:
                partName = "high_lod"; break;

            case OMVR.DetailLevel.High:
                partName = "medium_lod"; break;

            case OMVR.DetailLevel.Medium:
                partName = "low_lod"; break;

            case OMVR.DetailLevel.Low:
                partName = "lowest_lod"; break;
            }
            if (partName != null)
            {
                OSDMap meshParts = UnpackMesh(meshData);
                if (meshParts != null)
                {
                    if (meshParts.ContainsKey(partName))
                    {
                        byte[] meshBytes = meshParts[partName];
                        if (meshBytes != null)
                        {
                            ret = MeshSubMeshAsFacetedMesh(prim, meshBytes);
                        }
                    }
                }
            }
            return(ret);
        }
Exemple #12
0
        // The mesh reader code is organized so it can be used in several different ways:
        //
        // 1. Fetch the highest detail displayable mesh as a FacetedMesh:
        //      var facetedMesh = GenerateFacetedMeshMesh(prim, meshData);
        // 2. Get the header, examine the submeshes available, and extract the part
        //              desired (good if getting a different LOD of mesh):
        //      OSDMap meshParts = UnpackMesh(meshData);
        //      if (meshParts.ContainsKey("medium_lod"))
        //          var facetedMesh = MeshSubMeshAsFacetedMesh(prim, meshParts["medium_lod"]):
        // 3. Get a simple mesh from one of the submeshes (good if just getting a physics version):
        //      OSDMap meshParts = UnpackMesh(meshData);
        //      OMV.Mesh flatMesh = MeshSubMeshAsSimpleMesh(prim, meshParts["physics_mesh"]);
        //
        // "physics_convex" is specially formatted so there is another routine to unpack
        //              that section:
        //      OSDMap meshParts = UnpackMesh(meshData);
        //      if (meshParts.ContainsKey("physics_convex"))
        //          OSMap hullPieces = MeshSubMeshAsConvexHulls(prim, meshParts["physics_convex"]):
        //
        // LL mesh format detailed at http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format

        /// <summary>
        /// Create a mesh faceted mesh from the compressed mesh data.
        /// This returns the highest LOD renderable version of the mesh.
        ///
        /// The actual mesh data is fetched and passed to this
        /// routine since all the context for finding the data is elsewhere.
        /// </summary>
        /// <returns>The faceted mesh or null if can't do it</returns>
        public OMVR.FacetedMesh GenerateFacetedMeshMesh(OMV.Primitive prim, byte[] meshData)
        {
            OMVR.FacetedMesh ret       = null;
            OSDMap           meshParts = UnpackMesh(meshData);

            if (meshParts != null)
            {
                byte[]   meshBytes     = null;
                string[] decreasingLOD = { "high_lod", "medium_lod", "low_lod", "lowest_lod" };
                foreach (string partName in decreasingLOD)
                {
                    if (meshParts.ContainsKey(partName))
                    {
                        meshBytes = meshParts[partName];
                        break;
                    }
                }
                if (meshBytes != null)
                {
                    ret = MeshSubMeshAsFacetedMesh(prim, meshBytes);
                }
            }
            return(ret);
        }
Exemple #13
0
        //public void SetView(OpenMetaverse.Vector3 center, int roll, int pitch, int yaw, int zoom)
        //{
        //    this.Center = center;
        //    scrollRoll.Value = roll;
        //    scrollPitch.Value = pitch;
        //    scrollYaw.Value = yaw;
        //    scrollZoom.Value = zoom;
        //}

        public static FacetedMesh GenerateFacetedMesh(Primitive prim, OSDMap MeshData, DetailLevel LOD)
        {
            FacetedMesh ret = new FacetedMesh();

            ret.Faces = new List<Face>();
            ret.Prim = prim;
            ret.Profile = new Profile();
            ret.Profile.Faces = new List<ProfileFace>();
            ret.Profile.Positions = new List<OpenMetaverse.Vector3>();
            ret.Path = new OpenMetaverse.Rendering.Path();
            ret.Path.Points = new List<PathPoint>();

            try
            {
                OSD facesOSD = null;

                switch (LOD)
                {
                    default:
                    case DetailLevel.Highest:
                        facesOSD = MeshData["high_lod"];
                        break;

                    case DetailLevel.High:
                        facesOSD = MeshData["medium_lod"];
                        break;

                    case DetailLevel.Medium:
                        facesOSD = MeshData["low_lod"];
                        break;

                    case DetailLevel.Low:
                        facesOSD = MeshData["lowest_lod"];
                        break;
                }

                if (facesOSD == null || !(facesOSD is OSDArray))
                {
                    return ret;
                }

                OSDArray decodedMeshOsdArray = (OSDArray)facesOSD;

                for (int faceNr = 0; faceNr < decodedMeshOsdArray.Count; faceNr++)
                {
                    OSD subMeshOsd = decodedMeshOsdArray[faceNr];
                    Face oface = new Face();
                    oface.ID = faceNr;
                    oface.Vertices = new List<Vertex>();
                    oface.Indices = new List<ushort>();
                    oface.TextureFace = prim.Textures.GetFace((uint)faceNr);

                    if (subMeshOsd is OSDMap)
                    {
                        OSDMap subMeshMap = (OSDMap)subMeshOsd;

                        OpenMetaverse.Vector3 posMax = new OpenMetaverse.Vector3();
                        posMax = ((OSDMap)subMeshMap["PositionDomain"])["Max"];
                        OpenMetaverse.Vector3 posMin = new OpenMetaverse.Vector3();
                        posMin = ((OSDMap)subMeshMap["PositionDomain"])["Min"];

                        OpenMetaverse.Vector2 texPosMax = new OpenMetaverse.Vector2();
                        texPosMax = ((OSDMap)subMeshMap["TexCoord0Domain"])["Max"];
                        OpenMetaverse.Vector2 texPosMin = new OpenMetaverse.Vector2();
                        texPosMin = ((OSDMap)subMeshMap["TexCoord0Domain"])["Min"];


                        byte[] posBytes = subMeshMap["Position"];
                        byte[] norBytes = subMeshMap["Normal"];
                        byte[] texBytes = subMeshMap["TexCoord0"];

                        for (int i = 0; i < posBytes.Length; i += 6)
                        {
                            ushort uX = Utils.BytesToUInt16(posBytes, i);
                            ushort uY = Utils.BytesToUInt16(posBytes, i + 2);
                            ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);

                            Vertex vx = new Vertex();

                            vx.Position = new OpenMetaverse.Vector3(
                                Utils.UInt16ToFloat(uX, posMin.X, posMax.X),
                                Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y),
                                Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z));

                            ushort nX = Utils.BytesToUInt16(norBytes, i);
                            ushort nY = Utils.BytesToUInt16(norBytes, i + 2);
                            ushort nZ = Utils.BytesToUInt16(norBytes, i + 4);

                            vx.Normal = new OpenMetaverse.Vector3(
                                Utils.UInt16ToFloat(nX, posMin.X, posMax.X),
                                Utils.UInt16ToFloat(nY, posMin.Y, posMax.Y),
                                Utils.UInt16ToFloat(nZ, posMin.Z, posMax.Z));

                            var vertexIndexOffset = oface.Vertices.Count * 4;

                            if (texBytes != null && texBytes.Length >= vertexIndexOffset + 4)
                            {
                                ushort tX = Utils.BytesToUInt16(texBytes, vertexIndexOffset);
                                ushort tY = Utils.BytesToUInt16(texBytes, vertexIndexOffset + 2);

                                vx.TexCoord = new OpenMetaverse.Vector2(
                                    Utils.UInt16ToFloat(tX, texPosMin.X, texPosMax.X),
                                    Utils.UInt16ToFloat(tY, texPosMin.Y, texPosMax.Y));
                            }

                            oface.Vertices.Add(vx);
                        }

                        byte[] triangleBytes = subMeshMap["TriangleList"];
                        for (int i = 0; i < triangleBytes.Length; i += 6)
                        {
                            ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i));
                            oface.Indices.Add(v1);
                            ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2));
                            oface.Indices.Add(v2);
                            ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4));
                            oface.Indices.Add(v3);
                        }
                    }

                    ret.Faces.Add(oface);
                }

            }
            catch (Exception ex)
            {
                Logger.Log("Failed to decode mesh asset: " + ex.Message, Helpers.LogLevel.Warning);
            }

            return ret;
        }
Exemple #14
0
        List<MaterialInfo> GetMaterials(FacetedMesh obj)
        {
            var ret = new List<MaterialInfo>();

            for (int face_num = 0; face_num < obj.Faces.Count; face_num++)
            {
                var te = obj.Faces[(int)face_num].TextureFace;
                if (SkipTransparentFaces && te.RGBA.A < 0.01f)
                {
                    continue;
                }
                var mat = GetMaterial(te);
                if (!ret.Contains(mat))
                {
                    ret.Add(mat);
                }
            }
            return ret;
        }
Exemple #15
0
 List<int> GetFacesWithMaterial(FacetedMesh obj, MaterialInfo mat)
 {
     var ret = new List<int>();
     for (int face_num = 0; face_num < obj.Faces.Count; face_num++)
     {
         if (mat == GetMaterial(obj.Faces[(int)face_num].TextureFace))
         {
             ret.Add(face_num);
         }
     }
     return ret;
 }
Exemple #16
0
        void AddPolygons(XmlNode mesh, string geomID, string materialID, FacetedMesh obj, List<int> faces_to_include)
        {
            var polylist = mesh.AppendChild(Doc.CreateElement("polylist"));
            polylist.Attributes.Append(Doc.CreateAttribute("material")).InnerText = materialID;

            // Vertices semantic
            {
                var input = polylist.AppendChild(Doc.CreateElement("input"));
                input.Attributes.Append(Doc.CreateAttribute("semantic")).InnerText = "VERTEX";
                input.Attributes.Append(Doc.CreateAttribute("offset")).InnerText = "0";
                input.Attributes.Append(Doc.CreateAttribute("source")).InnerText = string.Format("#{0}-{1}", geomID, "vertices");
            }

            // Normals semantic
            {
                var input = polylist.AppendChild(Doc.CreateElement("input"));
                input.Attributes.Append(Doc.CreateAttribute("semantic")).InnerText = "NORMAL";
                input.Attributes.Append(Doc.CreateAttribute("offset")).InnerText = "0";
                input.Attributes.Append(Doc.CreateAttribute("source")).InnerText = string.Format("#{0}-{1}", geomID, "normals");
            }

            // UV semantic
            {
                var input = polylist.AppendChild(Doc.CreateElement("input"));
                input.Attributes.Append(Doc.CreateAttribute("semantic")).InnerText = "TEXCOORD";
                input.Attributes.Append(Doc.CreateAttribute("offset")).InnerText = "0";
                input.Attributes.Append(Doc.CreateAttribute("source")).InnerText = string.Format("#{0}-{1}", geomID, "map0");
            }

            // Save indices
            var vcount = polylist.AppendChild(Doc.CreateElement("vcount"));
            var p = polylist.AppendChild(Doc.CreateElement("p"));
            int index_offset = 0;
            int num_tris = 0;
            StringBuilder pBuilder = new StringBuilder();
            StringBuilder vcountBuilder = new StringBuilder();

            for (int face_num = 0; face_num < obj.Faces.Count; face_num++)
            {
                var face = obj.Faces[face_num];
                if (faces_to_include == null || faces_to_include.Contains(face_num))
                {
                    for (int i = 0; i < face.Indices.Count; i++)
                    {
                        int index = index_offset + face.Indices[i];
                        pBuilder.Append(index);
                        pBuilder.Append(" ");
                        if (i % 3 == 0)
                        {
                            vcountBuilder.Append("3 ");
                            num_tris++;
                        }
                    }
                }
                index_offset += face.Vertices.Count;
            }

            p.InnerText = pBuilder.ToString().TrimEnd();
            vcount.InnerText = vcountBuilder.ToString().TrimEnd();
            polylist.Attributes.Append(Doc.CreateAttribute("count")).InnerText = num_tris.ToString();
        }
    void ProcessPrim(FacetedMesh mesh)
    {
        if (objects.ContainsKey(mesh.Prim.LocalID))
            return;

        GameObject parent = null;
        if (mesh.Prim.ParentID != 0)
        {
            if (!objects.ContainsKey(mesh.Prim.ParentID))
            {
                if (newPrims.ContainsKey(mesh.Prim.ParentID) == false)
                    return;//temperarily ignore the prim
                ProcessPrim(newPrims[mesh.Prim.ParentID]);
            }
            parent = objects[mesh.Prim.ParentID];
        }
        else
            parent = primObjects;

        GameObject obj = new GameObject(mesh.Prim.LocalID.ToString());

        // Create vertices, uv, triangles for EACH FACE that stores the 3D data in Unity3D friendly format
        for (int j = 0; j < mesh.Faces.Count; j++)
        {
            Face face = mesh.Faces[j];
            GameObject faceObj = new GameObject("face" + j.ToString());
            faceObj.transform.parent = obj.transform;

            MeshRenderer mr = (faceObj.AddComponent("MeshRenderer") as MeshRenderer);
            if (Application.platform == RuntimePlatform.WindowsPlayer
                || Application.platform == RuntimePlatform.WindowsEditor)
            {
                UnityEngine.Material mat = m_textures.GetMaterial(face.TextureFace.TextureID);
                //Texture2D tex = m_textures.GetTexture2D(face.TextureFace.TextureID);
                if (mat != null)
                    mr.material = mat;
                else
                    mr.material = m_defaultObjectMat;
            }
            else
                mr.material = m_defaultObjectMat;

            UnityEngine.Mesh unityMesh = (faceObj.AddComponent("MeshFilter") as MeshFilter).mesh;

            Utility.MakeMesh(unityMesh, face, 0, face.Vertices.Count - 1, 0, face.Indices.Count - 1, 0);
        }
        //second life's child object's position and rotation is local, but scale are global.
        //So we have to set parent when setting position, and unset parent when setting rotation and scale.
        //Radegast explains well:
        //pos = parentPos + obj.InterpolatedPosition * parentRot;
        //rot = parentRot * obj.InterpolatedRotation;
        obj.transform.position = parent.transform.position +
            parent.transform.rotation * new UnityEngine.Vector3(mesh.Prim.Position.X, mesh.Prim.Position.Y, -mesh.Prim.Position.Z);

        //we invert the z axis, and Second Life rotatation is about right hand, but Unity rotation is about left hand, so we negate the x and y part of the quaternion.
        //You have to deeply understand the quaternion to understand this.
        obj.transform.rotation = parent.transform.rotation * new UnityEngine.Quaternion(-mesh.Prim.Rotation.X, -mesh.Prim.Rotation.Y, mesh.Prim.Rotation.Z, mesh.Prim.Rotation.W);
        obj.transform.localScale = new UnityEngine.Vector3(mesh.Prim.Scale.X, mesh.Prim.Scale.Y, mesh.Prim.Scale.Z);
        objects[mesh.Prim.LocalID] = obj;
        obj.transform.parent = primObjects.transform;
        //Debug.Log("prim " + mesh.Prim.LocalID.ToString() + ": Pos,"+mesh.Prim.Position.ToString() + " Rot,"+mesh.Prim.Rotation.ToString() + " Scale,"+mesh.Prim.Scale.ToString());
        //Sadly, when it comes to non-uniform scale parent, Unity will skew the child, so we cannot make hierachy of the objects.
    }
Exemple #18
0
        /// <summary>
        /// Given a FacetedMesh, create a DisplayableRenderable (a list of RenderableMesh's with materials).
        /// This also creates underlying MesnInfo, MaterialInfo, and ImageInfo in the AssetFetcher.
        /// </summary>
        /// <param name="assetFetcher"></param>
        /// <param name="fmesh">The FacetedMesh to convert into Renderables</param>
        /// <param name="defaultTexture">If a face doesn't have a texture defined, use this one.
        /// This is an OMV.Primitive.TextureEntryFace that includes a lot of OpenSimulator material info.</param>
        /// <param name="primScale">Scaling for the base prim that is used when appliying any texture
        /// to the face (updating UV).</param>
        /// <returns></returns>
        private DisplayableRenderable ConvertFacetedMeshToDisplayable(IAssetFetcher assetFetcher, OMVR.FacetedMesh fmesh,
                                                                      OMV.Primitive.TextureEntryFace defaultTexture, OMV.Vector3 primScale)
        {
            RenderableMeshGroup ret = new RenderableMeshGroup();

            ret.meshes.AddRange(fmesh.Faces.Where(face => face.Indices.Count > 0).Select(face => {
                return(ConvertFaceToRenderableMesh(face, assetFetcher, defaultTexture, primScale));
            }));
            // ConvOAR.Globals.log.DebugFormat("{0} ConvertFacetedMeshToDisplayable: complete. numMeshes={1}", _logHeader, ret.meshes.Count);
            return(ret);
        }
Exemple #19
0
        /// <summary>
        /// Generates a a series of faces, each face containing a mesh and
        /// metadata
        /// </summary>
        /// <param name="prim">Primitive to generate the mesh from</param>
        /// <param name="lod">Level of detail to generate the mesh at</param>
        /// <returns>The generated mesh</returns >
        public OMVR.FacetedMesh GenerateFacetedMesh(OMV.Primitive prim, OMVR.DetailLevel lod)
        {
            bool isSphere = ((OMV.ProfileCurve)(prim.PrimData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle);
            PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, true);
            if (newPrim == null)
                return null;

            int numViewerFaces = newPrim.viewerFaces.Count;
            int numPrimFaces = newPrim.numPrimFaces;

            for (uint i = 0; i < numViewerFaces; i++)
            {
                PrimMesher.ViewerFace vf = newPrim.viewerFaces[(int)i];

                if (isSphere)
                {
                    vf.uv1.U = (vf.uv1.U - 0.5f) * 2.0f;
                    vf.uv2.U = (vf.uv2.U - 0.5f) * 2.0f;
                    vf.uv3.U = (vf.uv3.U - 0.5f) * 2.0f;
                }
            }

            // copy the vertex information into OMVR.IRendering structures
            OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
            omvrmesh.Faces = new List<OMVR.Face>();
            omvrmesh.Prim = prim;
            omvrmesh.Profile = new OMVR.Profile();
            omvrmesh.Profile.Faces = new List<OMVR.ProfileFace>();
            omvrmesh.Profile.Positions = new List<OMV.Vector3>();
            omvrmesh.Path = new OMVR.Path();
            omvrmesh.Path.Points = new List<OMVR.PathPoint>();

            Dictionary<OMV.Vector3, int> vertexAccount = new Dictionary<OMV.Vector3, int>();
            for (int ii = 0; ii < numPrimFaces; ii++)
            {
                OMVR.Face oface = new OMVR.Face();
                oface.Vertices = new List<OMVR.Vertex>();
                oface.Indices = new List<ushort>();
                oface.TextureFace = prim.Textures.GetFace((uint)ii);
                int faceVertices = 0;
                vertexAccount.Clear();
                OMV.Vector3 pos;
                int indx;
                OMVR.Vertex vert;
                foreach (PrimMesher.ViewerFace vface in newPrim.viewerFaces)
                {
                    if (vface.primFaceNumber == ii)
                    {
                        faceVertices++;
                        pos = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z);
                        if (vertexAccount.ContainsKey(pos))
                        {
                            // we aleady have this vertex in the list. Just point the index at it
                            oface.Indices.Add((ushort)vertexAccount[pos]);
                        }
                        else
                        {
                            // the vertex is not in the list. Add it and the new index.
                            vert = new OMVR.Vertex();
                            vert.Position = pos;
                            vert.TexCoord = new OMV.Vector2(vface.uv1.U, 1.0f - vface.uv1.V);
                            vert.Normal = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z);
                            oface.Vertices.Add(vert);
                            indx = oface.Vertices.Count - 1;
                            vertexAccount.Add(pos, indx);
                            oface.Indices.Add((ushort)indx);
                        }

                        pos = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z);
                        if (vertexAccount.ContainsKey(pos))
                        {
                            oface.Indices.Add((ushort)vertexAccount[pos]);
                        }
                        else
                        {
                            vert = new OMVR.Vertex();
                            vert.Position = pos;
                            vert.TexCoord = new OMV.Vector2(vface.uv2.U, 1.0f - vface.uv2.V);
                            vert.Normal = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z);
                            oface.Vertices.Add(vert);
                            indx = oface.Vertices.Count - 1;
                            vertexAccount.Add(pos, indx);
                            oface.Indices.Add((ushort)indx);
                        }

                        pos = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z);
                        if (vertexAccount.ContainsKey(pos))
                        {
                            oface.Indices.Add((ushort)vertexAccount[pos]);
                        }
                        else
                        {
                            vert = new OMVR.Vertex();
                            vert.Position = pos;
                            vert.TexCoord = new OMV.Vector2(vface.uv3.U, 1.0f - vface.uv3.V);
                            vert.Normal = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z);
                            oface.Vertices.Add(vert);
                            indx = oface.Vertices.Count - 1;
                            vertexAccount.Add(pos, indx);
                            oface.Indices.Add((ushort)indx);
                        }
                    }
                }
                if (faceVertices > 0)
                {
                    oface.TextureFace = prim.Textures.FaceTextures[ii];
                    if (oface.TextureFace == null)
                    {
                        oface.TextureFace = prim.Textures.DefaultTexture;
                    }
                    oface.ID = ii;
                    omvrmesh.Faces.Add(oface);
                }
            }

            return omvrmesh;
        }
        /// <summary>
        /// Generates a a series of faces, each face containing a mesh and
        /// metadata
        /// </summary>
        /// <param name="prim">Primitive to generate the mesh from</param>
        /// <param name="lod">Level of detail to generate the mesh at</param>
        /// <returns>The generated mesh</returns >
        public OMVR.FacetedMesh GenerateFacetedMesh(OMV.Primitive prim, OMVR.DetailLevel lod)
        {
            bool isSphere = ((OMV.ProfileCurve)(prim.PrimData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle);
            PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, true);
            if (newPrim == null)
                return null;

            // copy the vertex information into OMVR.IRendering structures
            OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
            omvrmesh.Faces = new List<OMVR.Face>();
            omvrmesh.Prim = prim;
            omvrmesh.Profile = new OMVR.Profile();
            omvrmesh.Profile.Faces = new List<OMVR.ProfileFace>();
            omvrmesh.Profile.Positions = new List<OMV.Vector3>();
            omvrmesh.Path = new OMVR.Path();
            omvrmesh.Path.Points = new List<OMVR.PathPoint>();
            var indexer = newPrim.GetVertexIndexer();

            for (int i = 0; i < indexer.numPrimFaces; i++)
            {
                OMVR.Face oface = new OMVR.Face();
                oface.Vertices = new List<OMVR.Vertex>();
                oface.Indices = new List<ushort>();
                oface.TextureFace = prim.Textures.GetFace((uint)i);

                for (int j = 0; j < indexer.viewerVertices[i].Count; j++)
                {
                    var vert = new OMVR.Vertex();
                    var m = indexer.viewerVertices[i][j];
                    vert.Position = new Vector3(m.v.X, m.v.Y, m.v.Z);
                    vert.Normal = new Vector3(m.n.X, m.n.Y, m.n.Z);
                    vert.TexCoord = new OMV.Vector2(m.uv.U, 1.0f - m.uv.V);
                    oface.Vertices.Add(vert);
                }

                for (int j = 0; j < indexer.viewerPolygons[i].Count; j++)
                {
                    var p = indexer.viewerPolygons[i][j];
                    // Skip "degenerate faces" where the same vertex appears twice in the same tri
                    if (p.v1 == p.v2 || p.v1 == p.v2 || p.v2 == p.v3) continue;
                    oface.Indices.Add((ushort)p.v1);
                    oface.Indices.Add((ushort)p.v2);
                    oface.Indices.Add((ushort)p.v3);
                }

                omvrmesh.Faces.Add(oface);
            }

            return omvrmesh;
        }
Exemple #21
0
 /// <summary>
 /// Helper to parse mesh because no method exists
 /// to parse mesh assets to SimpleMesh.
 /// </summary>
 private void AddBoundingBoxOfFacetedMesh(FacetedMesh mesh, Primitive prim, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count)
 {
     if (mesh != null)
     {
         // Parse each face in mesh
         // since vertex array isn't populated.
         // This parses each unique vertex 3-6 times.
         foreach (Face face in mesh.Faces)
         {
             // Parse each vertex in face
             foreach (Vertex vertex in face.Vertices)
             {
                 Vector3 position = vertex.Position;
                 position = position * prim.Scale;
                 // Rotate part unless part is root
                 if (hasParent)
                     position = position * prim.Rotation;
                 position = position + prim.Position;
                 // Adjust lower and upper bounding box corners if needed
                 lower = Vector3.Min(lower, position);
                 upper = Vector3.Max(upper, position);
                 count++;
             }
         }
     }
 }
Exemple #22
0
        private void cboPrim_SelectedIndexChanged(object sender, EventArgs e)
        {
            CurrentPrim = (FacetedMesh)cboPrim.Items[cboPrim.SelectedIndex];
            PopulateFaceCombobox();

            glControl.Invalidate();
        }
Exemple #23
0
        /// <summary>
        /// Create a sculpty faceted mesh. The actual scuplt texture is fetched and passed to this
        /// routine since all the context for finding teh texture is elsewhere.
        /// </summary>
        /// <returns>The faceted mesh or null if can't do it</returns>
        public OMVR.FacetedMesh GenerateFacetedSculptMesh(Primitive prim, Bitmap scupltTexture, DetailLevel lod)
        {
            LibreMetaverse.PrimMesher.SculptMesh.SculptType smSculptType;
            switch (prim.Sculpt.Type)
            {
            case SculptType.Cylinder:
                smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.cylinder;
                break;

            case SculptType.Plane:
                smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.plane;
                break;

            case SculptType.Sphere:
                smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.sphere;
                break;

            case SculptType.Torus:
                smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.torus;
                break;

            default:
                smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.plane;
                break;
            }
            // The lod for sculpties is the resolution of the texture passed.
            // The first guess is 1:1 then lower resolutions after that
            // int mesherLod = (int)Math.Sqrt(scupltTexture.Width * scupltTexture.Height);
            int mesherLod = 32; // number used in Idealist viewer

            switch (lod)
            {
            case OMVR.DetailLevel.Highest:
                break;

            case OMVR.DetailLevel.High:
                break;

            case OMVR.DetailLevel.Medium:
                mesherLod /= 2;
                break;

            case OMVR.DetailLevel.Low:
                mesherLod /= 4;
                break;
            }
            LibreMetaverse.PrimMesher.SculptMesh newMesh =
                new LibreMetaverse.PrimMesher.SculptMesh(scupltTexture, smSculptType, mesherLod, true, prim.Sculpt.Mirror, prim.Sculpt.Invert);

            int numPrimFaces = 1;       // a scuplty has only one face

            // copy the vertex information into OMVR.IRendering structures
            FacetedMesh omvrmesh = new OMVR.FacetedMesh
            {
                Faces   = new List <OMVR.Face>(),
                Prim    = prim,
                Profile = new OMVR.Profile
                {
                    Faces     = new List <OMVR.ProfileFace>(),
                    Positions = new List <OMV.Vector3>()
                },
                Path = new OMVR.Path {
                    Points = new List <OMVR.PathPoint>()
                }
            };

            for (int ii = 0; ii < numPrimFaces; ii++)
            {
                Face oface = new OMVR.Face
                {
                    Vertices    = new List <OMVR.Vertex>(),
                    Indices     = new List <ushort>(),
                    TextureFace = prim.Textures.GetFace((uint)ii)
                };
                int faceVertices = newMesh.coords.Count;

                for (int j = 0; j < faceVertices; j++)
                {
                    var vert = new OMVR.Vertex
                    {
                        Position = new Vector3(newMesh.coords[j].X, newMesh.coords[j].Y, newMesh.coords[j].Z),
                        Normal   = new Vector3(newMesh.normals[j].X, newMesh.normals[j].Y, newMesh.normals[j].Z),
                        TexCoord = new Vector2(newMesh.uvs[j].U, newMesh.uvs[j].V)
                    };
                    oface.Vertices.Add(vert);
                }

                for (int j = 0; j < newMesh.faces.Count; j++)
                {
                    oface.Indices.Add((ushort)newMesh.faces[j].v1);
                    oface.Indices.Add((ushort)newMesh.faces[j].v2);
                    oface.Indices.Add((ushort)newMesh.faces[j].v3);
                }

                if (faceVertices > 0)
                {
                    oface.TextureFace = prim.Textures.FaceTextures[ii] ?? prim.Textures.DefaultTexture;
                    oface.ID          = ii;
                    omvrmesh.Faces.Add(oface);
                }
            }

            return(omvrmesh);
        }
        private OMVR.FacetedMesh GenerateIRendererMesh(int numPrimFaces, OMV.Primitive prim, 
                                             List<PrimMesher.ViewerFace> viewerFaces)
        {
            // copy the vertex information into OMVR.IRendering structures
            OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
            omvrmesh.Faces = new List<OMVR.Face>();
            omvrmesh.Prim = prim;
            omvrmesh.Profile = new OMVR.Profile();
            omvrmesh.Profile.Faces = new List<OMVR.ProfileFace>();
            omvrmesh.Profile.Positions = new List<OMV.Vector3>();
            omvrmesh.Path = new OMVR.Path();
            omvrmesh.Path.Points = new List<OMVR.PathPoint>();

            Dictionary<OMV.Vector3, int> vertexAccount = new Dictionary<OMV.Vector3, int>();
            OMV.Vector3 pos;
            int indx;
            OMVR.Vertex vert;
            for (int ii=0; ii<numPrimFaces; ii++) {
            OMVR.Face oface = new OMVR.Face();
            oface.Vertices = new List<OMVR.Vertex>();
            oface.Indices = new List<ushort>();
            if (prim.Textures == null) {
                oface.TextureFace = null;
            }
            else {
                oface.TextureFace = prim.Textures.GetFace((uint)ii);
            }
            int faceVertices = 0;
            vertexAccount.Clear();
            foreach (PrimMesher.ViewerFace vface in viewerFaces) {
                if (vface.primFaceNumber == ii) {
                    faceVertices++;
                    pos = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z);
                    if (vertexAccount.ContainsKey(pos)) {
                        oface.Indices.Add((ushort)vertexAccount[pos]);
                    }
                    else {
                        vert = new OMVR.Vertex();
                        vert.Position = pos;
                        vert.TexCoord = new OMV.Vector2(vface.uv1.U, vface.uv1.V);
                        vert.Normal = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z);
                        vert.Normal.Normalize();
                        oface.Vertices.Add(vert);
                        indx = oface.Vertices.Count - 1;
                        vertexAccount.Add(pos, indx);
                        oface.Indices.Add((ushort)indx);
                    }

                    pos = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z);
                    if (vertexAccount.ContainsKey(pos)) {
                        oface.Indices.Add((ushort)vertexAccount[pos]);
                    }
                    else {
                        vert = new OMVR.Vertex();
                        vert.Position = pos;
                        vert.TexCoord = new OMV.Vector2(vface.uv2.U, vface.uv2.V);
                        vert.Normal = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z);
                        vert.Normal.Normalize();
                        oface.Vertices.Add(vert);
                        indx = oface.Vertices.Count - 1;
                        vertexAccount.Add(pos, indx);
                        oface.Indices.Add((ushort)indx);
                    }

                    pos = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z);
                    if (vertexAccount.ContainsKey(pos)) {
                        oface.Indices.Add((ushort)vertexAccount[pos]);
                    }
                    else {
                        vert = new OMVR.Vertex();
                        vert.Position = pos;
                        vert.TexCoord = new OMV.Vector2(vface.uv3.U, vface.uv3.V);
                        vert.Normal = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z);
                        vert.Normal.Normalize();
                        oface.Vertices.Add(vert);
                        indx = oface.Vertices.Count - 1;
                        vertexAccount.Add(pos, indx);
                        oface.Indices.Add((ushort)indx);
                    }
                }
            }
            if (faceVertices > 0) {
                oface.TextureFace = null;
                if (prim.Textures != null) {
                    oface.TextureFace = prim.Textures.FaceTextures[ii];
                    if (oface.TextureFace == null) {
                        oface.TextureFace = prim.Textures.DefaultTexture;
                    }
                }
                oface.ID = ii;
                omvrmesh.Faces.Add(oface);
            }
            }

            return omvrmesh;
        }
Exemple #25
0
        /// <summary>
        /// Decodes mesh asset into FacetedMesh
        /// </summary>
        /// <param name="prim">Mesh primitive</param>
        /// <param name="meshAsset">Asset retrieved from the asset server</param>
        /// <param name="LOD">Level of detail</param>
        /// <param name="mesh">Resulting decoded FacetedMesh</param>
        /// <returns>True if mesh asset decoding was successful</returns>
        public static bool TryDecodeFromAsset(Primitive prim, AssetMesh meshAsset, DetailLevel LOD, out FacetedMesh mesh)
        {
            mesh = null;

            try
            {
                if (!meshAsset.Decode())
                {
                    return false;
                }

                OSDMap MeshData = meshAsset.MeshData;

                mesh = new FacetedMesh();

                mesh.Faces = new List<Face>();
                mesh.Prim = prim;
                mesh.Profile.Faces = new List<ProfileFace>();
                mesh.Profile.Positions = new List<Vector3>();
                mesh.Path.Points = new List<PathPoint>();

                OSD facesOSD = null;

                switch (LOD)
                {
                    default:
                    case DetailLevel.Highest:
                        facesOSD = MeshData["high_lod"];
                        break;

                    case DetailLevel.High:
                        facesOSD = MeshData["medium_lod"];
                        break;

                    case DetailLevel.Medium:
                        facesOSD = MeshData["low_lod"];
                        break;

                    case DetailLevel.Low:
                        facesOSD = MeshData["lowest_lod"];
                        break;
                }

                if (facesOSD == null || !(facesOSD is OSDArray))
                {
                    return false;
                }

                OSDArray decodedMeshOsdArray = (OSDArray)facesOSD;

                for (int faceNr = 0; faceNr < decodedMeshOsdArray.Count; faceNr++)
                {
                    OSD subMeshOsd = decodedMeshOsdArray[faceNr];

                    // Decode each individual face
                    if (subMeshOsd is OSDMap)
                    {
                        Face oface = new Face();
                        oface.ID = faceNr;
                        oface.Vertices = new List<Vertex>();
                        oface.Indices = new List<ushort>();
                        oface.TextureFace = prim.Textures.GetFace((uint)faceNr);

                        OSDMap subMeshMap = (OSDMap)subMeshOsd;

                        Vector3 posMax;
                        Vector3 posMin;

                        // If PositionDomain is not specified, the default is from -0.5 to 0.5
                        if (subMeshMap.ContainsKey("PositionDomain"))
                        {
                            posMax = ((OSDMap)subMeshMap["PositionDomain"])["Max"];
                            posMin = ((OSDMap)subMeshMap["PositionDomain"])["Min"];
                        }
                        else
                        {
                            posMax = new Vector3(0.5f, 0.5f, 0.5f);
                            posMin = new Vector3(-0.5f, -0.5f, -0.5f);
                        }

                        // Vertex positions
                        byte[] posBytes = subMeshMap["Position"];

                        // Normals
                        byte[] norBytes = null;
                        if (subMeshMap.ContainsKey("Normal"))
                        {
                            norBytes = subMeshMap["Normal"];
                        }

                        // UV texture map
                        Vector2 texPosMax = Vector2.Zero;
                        Vector2 texPosMin = Vector2.Zero;
                        byte[] texBytes = null;
                        if (subMeshMap.ContainsKey("TexCoord0"))
                        {
                            texBytes = subMeshMap["TexCoord0"];
                            texPosMax = ((OSDMap)subMeshMap["TexCoord0Domain"])["Max"];
                            texPosMin = ((OSDMap)subMeshMap["TexCoord0Domain"])["Min"];
                        }

                        // Extract the vertex position data
                        // If present normals and texture coordinates too
                        for (int i = 0; i < posBytes.Length; i += 6)
                        {
                            ushort uX = Utils.BytesToUInt16(posBytes, i);
                            ushort uY = Utils.BytesToUInt16(posBytes, i + 2);
                            ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);

                            Vertex vx = new Vertex();

                            vx.Position = new Vector3(
                                Utils.UInt16ToFloat(uX, posMin.X, posMax.X),
                                Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y),
                                Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z));

                            if (norBytes != null && norBytes.Length >= i + 4)
                            {
                                ushort nX = Utils.BytesToUInt16(norBytes, i);
                                ushort nY = Utils.BytesToUInt16(norBytes, i + 2);
                                ushort nZ = Utils.BytesToUInt16(norBytes, i + 4);

                                vx.Normal = new Vector3(
                                    Utils.UInt16ToFloat(nX, posMin.X, posMax.X),
                                    Utils.UInt16ToFloat(nY, posMin.Y, posMax.Y),
                                    Utils.UInt16ToFloat(nZ, posMin.Z, posMax.Z));
                            }

                            var vertexIndexOffset = oface.Vertices.Count * 4;

                            if (texBytes != null && texBytes.Length >= vertexIndexOffset + 4)
                            {
                                ushort tX = Utils.BytesToUInt16(texBytes, vertexIndexOffset);
                                ushort tY = Utils.BytesToUInt16(texBytes, vertexIndexOffset + 2);

                                vx.TexCoord = new Vector2(
                                    Utils.UInt16ToFloat(tX, texPosMin.X, texPosMax.X),
                                    Utils.UInt16ToFloat(tY, texPosMin.Y, texPosMax.Y));
                            }

                            oface.Vertices.Add(vx);
                        }

                        byte[] triangleBytes = subMeshMap["TriangleList"];
                        for (int i = 0; i < triangleBytes.Length; i += 6)
                        {
                            ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i));
                            oface.Indices.Add(v1);
                            ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2));
                            oface.Indices.Add(v2);
                            ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4));
                            oface.Indices.Add(v3);
                        }

                        mesh.Faces.Add(oface);
                    }
                }

            }
            catch (Exception ex)
            {
                Logger.Log("Failed to decode mesh asset: " + ex.Message, Helpers.LogLevel.Warning);
                return false;
            }

            return true;
        }
        /// <summary>
        /// Generates a a series of faces, each face containing a mesh and
        /// metadata
        /// </summary>
        /// <param name="prim">Primitive to generate the mesh from</param>
        /// <param name="lod">Level of detail to generate the mesh at</param>
        /// <returns>The generated mesh</returns >
        public OMVR.FacetedMesh GenerateFacetedMesh(OMV.Primitive prim, OMVR.DetailLevel lod)
        {
            bool isSphere = ((OMV.ProfileCurve)(prim.PrimData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle);

            PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, true);
            if (newPrim == null)
            {
                return(null);
            }

            int numViewerFaces = newPrim.viewerFaces.Count;
            int numPrimFaces   = newPrim.numPrimFaces;

            for (uint i = 0; i < numViewerFaces; i++)
            {
                PrimMesher.ViewerFace vf = newPrim.viewerFaces[(int)i];

                if (isSphere)
                {
                    vf.uv1.U = (vf.uv1.U - 0.5f) * 2.0f;
                    vf.uv2.U = (vf.uv2.U - 0.5f) * 2.0f;
                    vf.uv3.U = (vf.uv3.U - 0.5f) * 2.0f;
                }
            }

            // copy the vertex information into OMVR.IRendering structures
            OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
            omvrmesh.Faces             = new List <OMVR.Face>();
            omvrmesh.Prim              = prim;
            omvrmesh.Profile           = new OMVR.Profile();
            omvrmesh.Profile.Faces     = new List <OMVR.ProfileFace>();
            omvrmesh.Profile.Positions = new List <OMV.Vector3>();
            omvrmesh.Path              = new OMVR.Path();
            omvrmesh.Path.Points       = new List <OMVR.PathPoint>();

            Dictionary <OMV.Vector3, int> vertexAccount = new Dictionary <OMV.Vector3, int>();

            for (int ii = 0; ii < numPrimFaces; ii++)
            {
                OMVR.Face oface = new OMVR.Face();
                oface.Vertices    = new List <OMVR.Vertex>();
                oface.Indices     = new List <ushort>();
                oface.TextureFace = prim.Textures.GetFace((uint)ii);
                int faceVertices = 0;
                vertexAccount.Clear();
                OMV.Vector3 pos;
                int         indx;
                OMVR.Vertex vert;
                foreach (PrimMesher.ViewerFace vface in newPrim.viewerFaces)
                {
                    if (vface.primFaceNumber == ii)
                    {
                        faceVertices++;
                        pos = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z);
                        if (vertexAccount.ContainsKey(pos))
                        {
                            // we aleady have this vertex in the list. Just point the index at it
                            oface.Indices.Add((ushort)vertexAccount[pos]);
                        }
                        else
                        {
                            // the vertex is not in the list. Add it and the new index.
                            vert          = new OMVR.Vertex();
                            vert.Position = pos;
                            vert.TexCoord = new OMV.Vector2(vface.uv1.U, 1.0f - vface.uv1.V);
                            vert.Normal   = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z);
                            oface.Vertices.Add(vert);
                            indx = oface.Vertices.Count - 1;
                            vertexAccount.Add(pos, indx);
                            oface.Indices.Add((ushort)indx);
                        }

                        pos = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z);
                        if (vertexAccount.ContainsKey(pos))
                        {
                            oface.Indices.Add((ushort)vertexAccount[pos]);
                        }
                        else
                        {
                            vert          = new OMVR.Vertex();
                            vert.Position = pos;
                            vert.TexCoord = new OMV.Vector2(vface.uv2.U, 1.0f - vface.uv2.V);
                            vert.Normal   = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z);
                            oface.Vertices.Add(vert);
                            indx = oface.Vertices.Count - 1;
                            vertexAccount.Add(pos, indx);
                            oface.Indices.Add((ushort)indx);
                        }

                        pos = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z);
                        if (vertexAccount.ContainsKey(pos))
                        {
                            oface.Indices.Add((ushort)vertexAccount[pos]);
                        }
                        else
                        {
                            vert          = new OMVR.Vertex();
                            vert.Position = pos;
                            vert.TexCoord = new OMV.Vector2(vface.uv3.U, 1.0f - vface.uv3.V);
                            vert.Normal   = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z);
                            oface.Vertices.Add(vert);
                            indx = oface.Vertices.Count - 1;
                            vertexAccount.Add(pos, indx);
                            oface.Indices.Add((ushort)indx);
                        }
                    }
                }
                if (faceVertices > 0)
                {
                    oface.TextureFace = prim.Textures.FaceTextures[ii];
                    if (oface.TextureFace == null)
                    {
                        oface.TextureFace = prim.Textures.DefaultTexture;
                    }
                    oface.ID = ii;
                    omvrmesh.Faces.Add(oface);
                }
            }

            return(omvrmesh);
        }
        private OMVR.FacetedMesh GenerateIRendererMesh(int numPrimFaces, OMV.Primitive prim,
                                                       List <PrimMesher.ViewerFace> viewerFaces)
        {
            // copy the vertex information into OMVR.IRendering structures
            OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
            omvrmesh.Faces             = new List <OMVR.Face>();
            omvrmesh.Prim              = prim;
            omvrmesh.Profile           = new OMVR.Profile();
            omvrmesh.Profile.Faces     = new List <OMVR.ProfileFace>();
            omvrmesh.Profile.Positions = new List <OMV.Vector3>();
            omvrmesh.Path              = new OMVR.Path();
            omvrmesh.Path.Points       = new List <OMVR.PathPoint>();

            Dictionary <OMV.Vector3, int> vertexAccount = new Dictionary <OMV.Vector3, int>();

            OMV.Vector3 pos;
            int         indx;

            OMVR.Vertex vert;
            for (int ii = 0; ii < numPrimFaces; ii++)
            {
                OMVR.Face oface = new OMVR.Face();
                oface.Vertices = new List <OMVR.Vertex>();
                oface.Indices  = new List <ushort>();
                if (prim.Textures == null)
                {
                    oface.TextureFace = null;
                }
                else
                {
                    oface.TextureFace = prim.Textures.GetFace((uint)ii);
                }
                int faceVertices = 0;
                vertexAccount.Clear();
                foreach (PrimMesher.ViewerFace vface in viewerFaces)
                {
                    if (vface.primFaceNumber == ii)
                    {
                        faceVertices++;
                        pos = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z);
                        if (vertexAccount.ContainsKey(pos))
                        {
                            oface.Indices.Add((ushort)vertexAccount[pos]);
                        }
                        else
                        {
                            vert          = new OMVR.Vertex();
                            vert.Position = pos;
                            vert.TexCoord = new OMV.Vector2(vface.uv1.U, vface.uv1.V);
                            vert.Normal   = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z);
                            vert.Normal.Normalize();
                            oface.Vertices.Add(vert);
                            indx = oface.Vertices.Count - 1;
                            vertexAccount.Add(pos, indx);
                            oface.Indices.Add((ushort)indx);
                        }

                        pos = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z);
                        if (vertexAccount.ContainsKey(pos))
                        {
                            oface.Indices.Add((ushort)vertexAccount[pos]);
                        }
                        else
                        {
                            vert          = new OMVR.Vertex();
                            vert.Position = pos;
                            vert.TexCoord = new OMV.Vector2(vface.uv2.U, vface.uv2.V);
                            vert.Normal   = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z);
                            vert.Normal.Normalize();
                            oface.Vertices.Add(vert);
                            indx = oface.Vertices.Count - 1;
                            vertexAccount.Add(pos, indx);
                            oface.Indices.Add((ushort)indx);
                        }

                        pos = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z);
                        if (vertexAccount.ContainsKey(pos))
                        {
                            oface.Indices.Add((ushort)vertexAccount[pos]);
                        }
                        else
                        {
                            vert          = new OMVR.Vertex();
                            vert.Position = pos;
                            vert.TexCoord = new OMV.Vector2(vface.uv3.U, vface.uv3.V);
                            vert.Normal   = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z);
                            vert.Normal.Normalize();
                            oface.Vertices.Add(vert);
                            indx = oface.Vertices.Count - 1;
                            vertexAccount.Add(pos, indx);
                            oface.Indices.Add((ushort)indx);
                        }
                    }
                }
                if (faceVertices > 0)
                {
                    oface.TextureFace = null;
                    if (prim.Textures != null)
                    {
                        oface.TextureFace = prim.Textures.FaceTextures[ii];
                        if (oface.TextureFace == null)
                        {
                            oface.TextureFace = prim.Textures.DefaultTexture;
                        }
                    }
                    oface.ID = ii;
                    omvrmesh.Faces.Add(oface);
                }
            }

            return(omvrmesh);
        }
Exemple #28
0
        private bool TryPick(int x, int y, out FacetedMesh picked, out int faceID)
        {
            // Save old attributes
            GL.PushAttrib(AttribMask.AllAttribBits);

            // Disable some attributes to make the objects flat / solid color when they are drawn
            GL.Disable(EnableCap.Fog);
            GL.Disable(EnableCap.Texture2D);
            GL.Disable(EnableCap.Dither);
            GL.Disable(EnableCap.Lighting);
            GL.Disable(EnableCap.LineStipple);
            GL.Disable(EnableCap.PolygonStipple);
            GL.Disable(EnableCap.CullFace);
            GL.Disable(EnableCap.Blend);
            GL.Disable(EnableCap.AlphaTest);

            Render(true);

            byte[] color = new byte[4];
            GL.ReadPixels(x, glControl.Height - y, 1, 1, OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, color);

            GL.PopAttrib();

            int primID = Utils.BytesToUInt16(color, 0);
            faceID = color[2];

            picked = null;

            lock (Prims)
            {
                foreach (var mesh in Prims.Values)
                {
                    foreach (var face in mesh.Faces)
                    {
                        if (((FaceData)face.UserData).PickingID == primID)
                        {
                            picked = mesh;
                            break;
                        }
                    }

                    if (picked != null) break;
                }
            }

            return picked != null;
        }
Exemple #29
0
        public FacetedMesh GenerateFacetedSculptMesh(Primitive prim, Bitmap sculptTexture, DetailLevel lod)
        {
            if (prim.Sculpt == null || sculptTexture == null)
                return null;

            float detail = DETAIL_LEVELS[(int)lod];
            SculptType sculptType = prim.Sculpt.Type;

            int width = sculptTexture.Width;
            int height = sculptTexture.Height;

            int requestedSizeS, requestedSizeT;
            GetSculptMeshResolution(width, height, detail, out requestedSizeS, out requestedSizeT);

            Path path = GeneratePath(prim.PrimData, detail, true, requestedSizeS);
            Profile profile = GenerateProfile(prim.PrimData, path, detail, true, requestedSizeT);

            // We requested specific sizes, now see what we really got
            int sizeS = path.Points.Count;
            int sizeT = profile.Positions.Count;

            Debug.Assert(sizeS > 0 && sizeT > 0, "Bad sculpt mesh size " + sizeS + " " + sizeT);

            // Generate vertex positions
            List<Vertex> vertices = GenerateSculptMesh(width, height, sizeS, sizeT, sculptType, prim.Sculpt.Invert, prim.Sculpt.Mirror, sculptTexture);

            // TODO: Calculate the surface area to test if this is a degenerate mesh and if so, replace it with a placeholder

            List<Face> faces = CreateVolumeFaces(prim, path, profile, vertices, true);

            FacetedMesh mesh = new FacetedMesh();
            mesh.Faces = faces;
            mesh.Path = path;
            mesh.Profile = profile;
            mesh.Prim = prim;

            return mesh;
        }
Exemple #30
0
 /// <summary>
 /// Helper to parse FacetedMesh for ray hits.
 /// </summary>
 private void AddRayInFacetedMesh(FacetedMesh mesh, RayTrans rayTrans, ref List<RayHit> rayHits)
 {
     if (mesh != null)
     {
         foreach (Face face in mesh.Faces)
         {
             for (int i = 0; i < face.Indices.Count; i += 3)
             {
                 Tri triangle = new Tri();
                 triangle.p1 = face.Vertices[face.Indices[i]].Position;
                 triangle.p2 = face.Vertices[face.Indices[i + 1]].Position;
                 triangle.p3 = face.Vertices[face.Indices[i + 2]].Position;
                 AddRayInTri(triangle, rayTrans, ref rayHits);
             }
         }
     }
 }
Exemple #31
0
        /// <summary>
        /// Create a sculpty faceted mesh. The actual scuplt texture is fetched and passed to this
        /// routine since all the context for finding teh texture is elsewhere.
        /// </summary>
        /// <returns>The faceted mesh or null if can't do it</returns>
        public OMVR.FacetedMesh GenerateFacetedSculptMesh(OMV.Primitive prim, System.Drawing.Bitmap scupltTexture, OMVR.DetailLevel lod)
        {
            byte sculptType = (byte)prim.Sculpt.Type;
            bool mirror = ((sculptType & 128) != 0);
            bool invert = ((sculptType & 64) != 0);
            // mirror = false; // TODO: libomv doesn't support these and letting them flop around causes problems
            // invert = false;
            OMV.SculptType omSculptType = (OMV.SculptType)(sculptType & 0x07);

            PrimMesher.SculptMesh.SculptType smSculptType;
            switch (omSculptType)
            {
                case OpenMetaverse.SculptType.Cylinder:
                    smSculptType = PrimMesher.SculptMesh.SculptType.cylinder;
                    break;
                case OpenMetaverse.SculptType.Plane:
                    smSculptType = PrimMesher.SculptMesh.SculptType.plane;
                    break;
                case OpenMetaverse.SculptType.Sphere:
                    smSculptType = PrimMesher.SculptMesh.SculptType.sphere;
                    break;
                case OpenMetaverse.SculptType.Torus:
                    smSculptType = PrimMesher.SculptMesh.SculptType.torus;
                    break;
                default:
                    smSculptType = PrimMesher.SculptMesh.SculptType.plane;
                    break;
            }
            // The lod for sculpties is the resolution of the texture passed.
            // The first guess is 1:1 then lower resolutions after that
            // int mesherLod = (int)Math.Sqrt(scupltTexture.Width * scupltTexture.Height);
            int mesherLod = 32; // number used in Idealist viewer
            switch (lod)
            {
                case OMVR.DetailLevel.Highest:
                    break;
                case OMVR.DetailLevel.High:
                    break;
                case OMVR.DetailLevel.Medium:
                    mesherLod /= 2;
                    break;
                case OMVR.DetailLevel.Low:
                    mesherLod /= 4;
                    break;
            }
            PrimMesher.SculptMesh newMesh =
                new PrimMesher.SculptMesh(scupltTexture, smSculptType, mesherLod, true, mirror, invert);

            int numPrimFaces = 1;       // a scuplty has only one face

            // copy the vertex information into OMVR.IRendering structures
            OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
            omvrmesh.Faces = new List<OMVR.Face>();
            omvrmesh.Prim = prim;
            omvrmesh.Profile = new OMVR.Profile();
            omvrmesh.Profile.Faces = new List<OMVR.ProfileFace>();
            omvrmesh.Profile.Positions = new List<OMV.Vector3>();
            omvrmesh.Path = new OMVR.Path();
            omvrmesh.Path.Points = new List<OMVR.PathPoint>();

            for (int ii = 0; ii < numPrimFaces; ii++)
            {
                OMVR.Face oface = new OMVR.Face();
                oface.Vertices = new List<OMVR.Vertex>();
                oface.Indices = new List<ushort>();
                oface.TextureFace = prim.Textures.GetFace((uint)ii);
                int faceVertices = 0;
                foreach (PrimMesher.ViewerFace vface in newMesh.viewerFaces)
                {
                    OMVR.Vertex vert = new OMVR.Vertex();
                    vert.Position = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z);
                    vert.TexCoord = new OMV.Vector2(vface.uv1.U, 1.0f - vface.uv1.V);
                    vert.Normal = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z);
                    oface.Vertices.Add(vert);

                    vert = new OMVR.Vertex();
                    vert.Position = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z);
                    vert.TexCoord = new OMV.Vector2(vface.uv2.U, 1.0f - vface.uv2.V);
                    vert.Normal = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z);
                    oface.Vertices.Add(vert);

                    vert = new OMVR.Vertex();
                    vert.Position = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z);
                    vert.TexCoord = new OMV.Vector2(vface.uv3.U, 1.0f - vface.uv3.V);
                    vert.Normal = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z);
                    oface.Vertices.Add(vert);

                    oface.Indices.Add((ushort)(faceVertices * 3 + 0));
                    oface.Indices.Add((ushort)(faceVertices * 3 + 1));
                    oface.Indices.Add((ushort)(faceVertices * 3 + 2));
                    faceVertices++;
                }
                if (faceVertices > 0)
                {
                    oface.TextureFace = prim.Textures.FaceTextures[ii];
                    if (oface.TextureFace == null)
                    {
                        oface.TextureFace = prim.Textures.DefaultTexture;
                    }
                    oface.ID = ii;
                    omvrmesh.Faces.Add(oface);
                }
            }

            return omvrmesh;
        }
Exemple #32
0
        /// <summary>
        /// Decodes mesh asset into FacetedMesh
        /// </summary>
        /// <param name="prim">Mesh primitive</param>
        /// <param name="meshAsset">Asset retrieved from the asset server</param>
        /// <param name="LOD">Level of detail</param>
        /// <param name="mesh">Resulting decoded FacetedMesh</param>
        /// <returns>True if mesh asset decoding was successful</returns>
        public static bool TryDecodeFromAsset(Primitive prim, AssetMesh meshAsset, DetailLevel LOD, out FacetedMesh mesh)
        {
            mesh = null;

            try
            {
                if (!meshAsset.Decode())
                {
                    return(false);
                }

                OSDMap MeshData = meshAsset.MeshData;

                mesh = new FacetedMesh();

                mesh.Faces             = new List <Face>();
                mesh.Prim              = prim;
                mesh.Profile.Faces     = new List <ProfileFace>();
                mesh.Profile.Positions = new List <Vector3>();
                mesh.Path.Points       = new List <PathPoint>();

                OSD facesOSD = null;

                switch (LOD)
                {
                default:
                case DetailLevel.Highest:
                    facesOSD = MeshData["high_lod"];
                    break;

                case DetailLevel.High:
                    facesOSD = MeshData["medium_lod"];
                    break;

                case DetailLevel.Medium:
                    facesOSD = MeshData["low_lod"];
                    break;

                case DetailLevel.Low:
                    facesOSD = MeshData["lowest_lod"];
                    break;
                }

                if (facesOSD == null || !(facesOSD is OSDArray))
                {
                    return(false);
                }

                OSDArray decodedMeshOsdArray = (OSDArray)facesOSD;

                for (int faceNr = 0; faceNr < decodedMeshOsdArray.Count; faceNr++)
                {
                    OSD subMeshOsd = decodedMeshOsdArray[faceNr];

                    // Decode each individual face
                    if (subMeshOsd is OSDMap)
                    {
                        Face oface = new Face();
                        oface.ID          = faceNr;
                        oface.Vertices    = new List <Vertex>();
                        oface.Indices     = new List <ushort>();
                        oface.TextureFace = prim.Textures.GetFace((uint)faceNr);

                        OSDMap subMeshMap = (OSDMap)subMeshOsd;

                        Vector3 posMax;
                        Vector3 posMin;

                        // If PositionDomain is not specified, the default is from -0.5 to 0.5
                        if (subMeshMap.ContainsKey("PositionDomain"))
                        {
                            posMax = ((OSDMap)subMeshMap["PositionDomain"])["Max"];
                            posMin = ((OSDMap)subMeshMap["PositionDomain"])["Min"];
                        }
                        else
                        {
                            posMax = new Vector3(0.5f, 0.5f, 0.5f);
                            posMin = new Vector3(-0.5f, -0.5f, -0.5f);
                        }

                        // Vertex positions
                        byte[] posBytes = subMeshMap["Position"];

                        // Normals
                        byte[] norBytes = null;
                        if (subMeshMap.ContainsKey("Normal"))
                        {
                            norBytes = subMeshMap["Normal"];
                        }

                        // UV texture map
                        Vector2 texPosMax = Vector2.Zero;
                        Vector2 texPosMin = Vector2.Zero;
                        byte[]  texBytes  = null;
                        if (subMeshMap.ContainsKey("TexCoord0"))
                        {
                            texBytes  = subMeshMap["TexCoord0"];
                            texPosMax = ((OSDMap)subMeshMap["TexCoord0Domain"])["Max"];
                            texPosMin = ((OSDMap)subMeshMap["TexCoord0Domain"])["Min"];
                        }

                        // Extract the vertex position data
                        // If present normals and texture coordinates too
                        for (int i = 0; i < posBytes.Length; i += 6)
                        {
                            ushort uX = Utils.BytesToUInt16(posBytes, i);
                            ushort uY = Utils.BytesToUInt16(posBytes, i + 2);
                            ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);

                            Vertex vx = new Vertex();

                            vx.Position = new Vector3(
                                Utils.UInt16ToFloat(uX, posMin.X, posMax.X),
                                Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y),
                                Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z));

                            if (norBytes != null && norBytes.Length >= i + 4)
                            {
                                ushort nX = Utils.BytesToUInt16(norBytes, i);
                                ushort nY = Utils.BytesToUInt16(norBytes, i + 2);
                                ushort nZ = Utils.BytesToUInt16(norBytes, i + 4);

                                vx.Normal = new Vector3(
                                    Utils.UInt16ToFloat(nX, posMin.X, posMax.X),
                                    Utils.UInt16ToFloat(nY, posMin.Y, posMax.Y),
                                    Utils.UInt16ToFloat(nZ, posMin.Z, posMax.Z));
                            }

                            var vertexIndexOffset = oface.Vertices.Count * 4;

                            if (texBytes != null && texBytes.Length >= vertexIndexOffset + 4)
                            {
                                ushort tX = Utils.BytesToUInt16(texBytes, vertexIndexOffset);
                                ushort tY = Utils.BytesToUInt16(texBytes, vertexIndexOffset + 2);

                                vx.TexCoord = new Vector2(
                                    Utils.UInt16ToFloat(tX, texPosMin.X, texPosMax.X),
                                    Utils.UInt16ToFloat(tY, texPosMin.Y, texPosMax.Y));
                            }

                            oface.Vertices.Add(vx);
                        }

                        byte[] triangleBytes = subMeshMap["TriangleList"];
                        for (int i = 0; i < triangleBytes.Length; i += 6)
                        {
                            ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i));
                            oface.Indices.Add(v1);
                            ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2));
                            oface.Indices.Add(v2);
                            ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4));
                            oface.Indices.Add(v3);
                        }

                        mesh.Faces.Add(oface);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Log("Failed to decode mesh asset: " + ex.Message, Helpers.LogLevel.Warning);
                return(false);
            }

            return(true);
        }
Exemple #33
0
 private void LoadDebugPrim()
 {
     Prims = new List<FacetedMesh>();
     Primitive prim = new Primitive();
     prim.Textures = new Primitive.TextureEntry(UUID.Zero);
     prim.Scale = Vector3.One;
     prim.PrimData = ObjectManager.BuildBasicShape(PrimType.Cylinder);
     prim.PrimData.ProfileHollow = 0.95f;
     SimpleMesh simpleMesh = Render.Plugin.GenerateSimpleMesh(prim, DetailLevel.High);
     FacetedMesh facetedMesh = new FacetedMesh();
     facetedMesh.Faces = new List<Face> { new Face { Vertices = simpleMesh.Vertices, Indices = simpleMesh.Indices } };
     facetedMesh.Path = simpleMesh.Path;
     facetedMesh.Profile = simpleMesh.Profile;
     facetedMesh.Prim = prim;
     LoadMesh(facetedMesh, ".");
     PopulatePrimCombobox();
     glControl.Invalidate();
 }
Exemple #34
0
        /// <summary>
        /// Create a sculpty faceted mesh. The actual scuplt texture is fetched and passed to this
        /// routine since all the context for finding teh texture is elsewhere.
        /// </summary>
        /// <returns>The faceted mesh or null if can't do it</returns>
        public OMVR.FacetedMesh GenerateFacetedSculptMesh(OMV.Primitive prim, System.Drawing.Bitmap scupltTexture, OMVR.DetailLevel lod)
        {
            PrimMesher.SculptMesh.SculptType smSculptType;
            switch (prim.Sculpt.Type)
            {
                case OpenMetaverse.SculptType.Cylinder:
                    smSculptType = PrimMesher.SculptMesh.SculptType.cylinder;
                    break;
                case OpenMetaverse.SculptType.Plane:
                    smSculptType = PrimMesher.SculptMesh.SculptType.plane;
                    break;
                case OpenMetaverse.SculptType.Sphere:
                    smSculptType = PrimMesher.SculptMesh.SculptType.sphere;
                    break;
                case OpenMetaverse.SculptType.Torus:
                    smSculptType = PrimMesher.SculptMesh.SculptType.torus;
                    break;
                default:
                    smSculptType = PrimMesher.SculptMesh.SculptType.plane;
                    break;
            }
            // The lod for sculpties is the resolution of the texture passed.
            // The first guess is 1:1 then lower resolutions after that
            // int mesherLod = (int)Math.Sqrt(scupltTexture.Width * scupltTexture.Height);
            int mesherLod = 32; // number used in Idealist viewer
            switch (lod)
            {
                case OMVR.DetailLevel.Highest:
                    break;
                case OMVR.DetailLevel.High:
                    break;
                case OMVR.DetailLevel.Medium:
                    mesherLod /= 2;
                    break;
                case OMVR.DetailLevel.Low:
                    mesherLod /= 4;
                    break;
            }
            PrimMesher.SculptMesh newMesh =
                new PrimMesher.SculptMesh(scupltTexture, smSculptType, mesherLod, true, prim.Sculpt.Mirror, prim.Sculpt.Invert);

            int numPrimFaces = 1;       // a scuplty has only one face

            // copy the vertex information into OMVR.IRendering structures
            OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
            omvrmesh.Faces = new List<OMVR.Face>();
            omvrmesh.Prim = prim;
            omvrmesh.Profile = new OMVR.Profile();
            omvrmesh.Profile.Faces = new List<OMVR.ProfileFace>();
            omvrmesh.Profile.Positions = new List<OMV.Vector3>();
            omvrmesh.Path = new OMVR.Path();
            omvrmesh.Path.Points = new List<OMVR.PathPoint>();

            Dictionary<OMVR.Vertex, int> vertexAccount = new Dictionary<OMVR.Vertex, int>();


            for (int ii = 0; ii < numPrimFaces; ii++)
            {
                vertexAccount.Clear();
                OMVR.Face oface = new OMVR.Face();
                oface.Vertices = new List<OMVR.Vertex>();
                oface.Indices = new List<ushort>();
                oface.TextureFace = prim.Textures.GetFace((uint)ii);
                int faceVertices = newMesh.coords.Count;
                OMVR.Vertex vert;

                for (int j = 0; j < faceVertices; j++)
                {
                    vert = new OMVR.Vertex();
                    vert.Position = new Vector3(newMesh.coords[j].X, newMesh.coords[j].Y, newMesh.coords[j].Z);
                    vert.Normal = new Vector3(newMesh.normals[j].X, newMesh.normals[j].Y, newMesh.normals[j].Z);
                    vert.TexCoord = new Vector2(newMesh.uvs[j].U, newMesh.uvs[j].V);
                    oface.Vertices.Add(vert);
                }

                for (int j = 0; j < newMesh.faces.Count; j++)
                {
                    oface.Indices.Add((ushort)newMesh.faces[j].v1);
                    oface.Indices.Add((ushort)newMesh.faces[j].v2);
                    oface.Indices.Add((ushort)newMesh.faces[j].v3);
                }

                if (faceVertices > 0)
                {
                    oface.TextureFace = prim.Textures.FaceTextures[ii];
                    if (oface.TextureFace == null)
                    {
                        oface.TextureFace = prim.Textures.DefaultTexture;
                    }
                    oface.ID = ii;
                    omvrmesh.Faces.Add(oface);
                }
            }

            return omvrmesh;
        }
Exemple #35
0
        private void LoadMesh(FacetedMesh mesh, string basePath)
        {
            // Create a FaceData struct for each face that stores the 3D data
            // in a Tao.OpenGL friendly format
            for (int j = 0; j < mesh.Faces.Count; j++)
            {
                Face face = mesh.Faces[j];
                FaceData data = new FaceData();

                // Vertices for this face
                data.Vertices = new float[face.Vertices.Count * 3];
                for (int k = 0; k < face.Vertices.Count; k++)
                {
                    data.Vertices[k * 3 + 0] = face.Vertices[k].Position.X;
                    data.Vertices[k * 3 + 1] = face.Vertices[k].Position.Y;
                    data.Vertices[k * 3 + 2] = face.Vertices[k].Position.Z;
                }

                // Indices for this face
                data.Indices = face.Indices.ToArray();

                // Texture transform for this face
                Primitive.TextureEntryFace teFace = mesh.Prim.Textures.GetFace((uint)j);
                Render.Plugin.TransformTexCoords(face.Vertices, face.Center, teFace);

                // Texcoords for this face
                data.TexCoords = new float[face.Vertices.Count * 2];
                for (int k = 0; k < face.Vertices.Count; k++)
                {
                    data.TexCoords[k * 2 + 0] = face.Vertices[k].TexCoord.X;
                    data.TexCoords[k * 2 + 1] = face.Vertices[k].TexCoord.Y;
                }

                // Texture for this face
                if (!String.IsNullOrEmpty(basePath) && LoadTexture(basePath, teFace.TextureID, ref data.Texture))
                {
                    Bitmap bitmap = new Bitmap(data.Texture);
                    bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
                    Rectangle rectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
                    BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

                    Gl.glGenTextures(1, out data.TexturePointer);
                    Gl.glBindTexture(Gl.GL_TEXTURE_2D, data.TexturePointer);

                    Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_LINEAR);
                    Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
                    Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
                    Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
                    Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_GENERATE_MIPMAP, Gl.GL_TRUE);

                    Glu.gluBuild2DMipmaps(Gl.GL_TEXTURE_2D, Gl.GL_RGB8, bitmap.Width, bitmap.Height, Gl.GL_BGR, Gl.GL_UNSIGNED_BYTE, bitmapData.Scan0);

                    bitmap.UnlockBits(bitmapData);
                    bitmap.Dispose();
                }

                // Set the UserData for this face to our FaceData struct
                face.UserData = data;
                mesh.Faces[j] = face;
            }

            Prims.Add(mesh);
        }
Exemple #36
0
        /// <summary>
        /// Create a sculpty faceted mesh. The actual scuplt texture is fetched and passed to this
        /// routine since all the context for finding teh texture is elsewhere.
        /// </summary>
        /// <returns>The faceted mesh or null if can't do it</returns>
        public OMVR.FacetedMesh GenerateFacetedSculptMesh(OMV.Primitive prim, System.Drawing.Bitmap scupltTexture, OMVR.DetailLevel lod)
        {
            byte sculptType = (byte)prim.Sculpt.Type;
            bool mirror     = ((sculptType & 128) != 0);
            bool invert     = ((sculptType & 64) != 0);

            // mirror = false; // TODO: libomv doesn't support these and letting them flop around causes problems
            // invert = false;
            OMV.SculptType omSculptType = (OMV.SculptType)(sculptType & 0x07);

            PrimMesher.SculptMesh.SculptType smSculptType;
            switch (omSculptType)
            {
            case OpenMetaverse.SculptType.Cylinder:
                smSculptType = PrimMesher.SculptMesh.SculptType.cylinder;
                break;

            case OpenMetaverse.SculptType.Plane:
                smSculptType = PrimMesher.SculptMesh.SculptType.plane;
                break;

            case OpenMetaverse.SculptType.Sphere:
                smSculptType = PrimMesher.SculptMesh.SculptType.sphere;
                break;

            case OpenMetaverse.SculptType.Torus:
                smSculptType = PrimMesher.SculptMesh.SculptType.torus;
                break;

            default:
                smSculptType = PrimMesher.SculptMesh.SculptType.plane;
                break;
            }
            // The lod for sculpties is the resolution of the texture passed.
            // The first guess is 1:1 then lower resolutions after that
            // int mesherLod = (int)Math.Sqrt(scupltTexture.Width * scupltTexture.Height);
            int mesherLod = 32; // number used in Idealist viewer

            switch (lod)
            {
            case OMVR.DetailLevel.Highest:
                break;

            case OMVR.DetailLevel.High:
                break;

            case OMVR.DetailLevel.Medium:
                mesherLod /= 2;
                break;

            case OMVR.DetailLevel.Low:
                mesherLod /= 4;
                break;
            }
            PrimMesher.SculptMesh newMesh =
                new PrimMesher.SculptMesh(scupltTexture, smSculptType, mesherLod, true, mirror, invert);

            int numPrimFaces = 1;       // a scuplty has only one face

            // copy the vertex information into OMVR.IRendering structures
            OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
            omvrmesh.Faces             = new List <OMVR.Face>();
            omvrmesh.Prim              = prim;
            omvrmesh.Profile           = new OMVR.Profile();
            omvrmesh.Profile.Faces     = new List <OMVR.ProfileFace>();
            omvrmesh.Profile.Positions = new List <OMV.Vector3>();
            omvrmesh.Path              = new OMVR.Path();
            omvrmesh.Path.Points       = new List <OMVR.PathPoint>();

            for (int ii = 0; ii < numPrimFaces; ii++)
            {
                OMVR.Face oface = new OMVR.Face();
                oface.Vertices    = new List <OMVR.Vertex>();
                oface.Indices     = new List <ushort>();
                oface.TextureFace = prim.Textures.GetFace((uint)ii);
                int faceVertices = 0;
                foreach (PrimMesher.ViewerFace vface in newMesh.viewerFaces)
                {
                    OMVR.Vertex vert = new OMVR.Vertex();
                    vert.Position = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z);
                    vert.TexCoord = new OMV.Vector2(vface.uv1.U, 1.0f - vface.uv1.V);
                    vert.Normal   = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z);
                    oface.Vertices.Add(vert);

                    vert          = new OMVR.Vertex();
                    vert.Position = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z);
                    vert.TexCoord = new OMV.Vector2(vface.uv2.U, 1.0f - vface.uv2.V);
                    vert.Normal   = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z);
                    oface.Vertices.Add(vert);

                    vert          = new OMVR.Vertex();
                    vert.Position = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z);
                    vert.TexCoord = new OMV.Vector2(vface.uv3.U, 1.0f - vface.uv3.V);
                    vert.Normal   = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z);
                    oface.Vertices.Add(vert);

                    oface.Indices.Add((ushort)(faceVertices * 3 + 0));
                    oface.Indices.Add((ushort)(faceVertices * 3 + 1));
                    oface.Indices.Add((ushort)(faceVertices * 3 + 2));
                    faceVertices++;
                }
                if (faceVertices > 0)
                {
                    oface.TextureFace = prim.Textures.FaceTextures[ii];
                    if (oface.TextureFace == null)
                    {
                        oface.TextureFace = prim.Textures.DefaultTexture;
                    }
                    oface.ID = ii;
                    omvrmesh.Faces.Add(oface);
                }
            }

            return(omvrmesh);
        }
Exemple #37
0
        /// <summary>
        /// Generates a a series of faces, each face containing a mesh and
        /// metadata
        /// </summary>
        /// <param name="prim">Primitive to generate the mesh from</param>
        /// <param name="lod">Level of detail to generate the mesh at</param>
        /// <returns>The generated mesh</returns >
        public OMVR.FacetedMesh GenerateFacetedMesh(OMV.Primitive prim, OMVR.DetailLevel lod)
        {

            OMV.Primitive.ConstructionData primData = prim.PrimData;
            int sides = 4;
            int hollowsides = 4;

            float profileBegin = primData.ProfileBegin;
            float profileEnd = primData.ProfileEnd;
            bool isSphere = false;

            if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.Circle)
            {
                switch (lod)
                {
                    case OMVR.DetailLevel.Low:
                        sides = 6;
                        break;
                    case OMVR.DetailLevel.Medium:
                        sides = 12;
                        break;
                    default:
                        sides = 24;
                        break;
                }
            }
            else if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.EqualTriangle)
                sides = 3;
            else if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle)
            {
                // half circle, prim is a sphere
                isSphere = true;
                switch (lod)
                {
                    case OMVR.DetailLevel.Low:
                        sides = 6;
                        break;
                    case OMVR.DetailLevel.Medium:
                        sides = 12;
                        break;
                    default:
                        sides = 24;
                        break;
                }
                profileBegin = 0.5f * profileBegin + 0.5f;
                profileEnd = 0.5f * profileEnd + 0.5f;
            }

            if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Same)
                hollowsides = sides;
            else if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Circle)
            {
                switch (lod)
                {
                    case OMVR.DetailLevel.Low:
                        hollowsides = 6;
                        break;
                    case OMVR.DetailLevel.Medium:
                        hollowsides = 12;
                        break;
                    default:
                        hollowsides = 24;
                        break;
                }
            }
            else if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Triangle)
                hollowsides = 3;

            PrimMesher.PrimMesh newPrim = new PrimMesher.PrimMesh(sides, profileBegin, profileEnd, (float)primData.ProfileHollow, hollowsides);
            newPrim.viewerMode = true;
            newPrim.holeSizeX = primData.PathScaleX;
            newPrim.holeSizeY = primData.PathScaleY;
            newPrim.pathCutBegin = primData.PathBegin;
            newPrim.pathCutEnd = primData.PathEnd;
            newPrim.topShearX = primData.PathShearX;
            newPrim.topShearY = primData.PathShearY;
            newPrim.radius = primData.PathRadiusOffset;
            newPrim.revolutions = primData.PathRevolutions;
            newPrim.skew = primData.PathSkew;
            switch (lod)
            {
                case OMVR.DetailLevel.Low:
                    newPrim.stepsPerRevolution = 6;
                    break;
                case OMVR.DetailLevel.Medium:
                    newPrim.stepsPerRevolution = 12;
                    break;
                default:
                    newPrim.stepsPerRevolution = 24;
                    break;
            }

            if ((primData.PathCurve == OMV.PathCurve.Line) || (primData.PathCurve == OMV.PathCurve.Flexible))
            {
                newPrim.taperX = 1.0f - primData.PathScaleX;
                newPrim.taperY = 1.0f - primData.PathScaleY;
                newPrim.twistBegin = (int)(180 * primData.PathTwistBegin);
                newPrim.twistEnd = (int)(180 * primData.PathTwist);
                newPrim.ExtrudeLinear();
            }
            else
            {
                newPrim.taperX = primData.PathTaperX;
                newPrim.taperY = primData.PathTaperY;
                newPrim.twistBegin = (int)(360 * primData.PathTwistBegin);
                newPrim.twistEnd = (int)(360 * primData.PathTwist);
                newPrim.ExtrudeCircular();
            }

            int numViewerFaces = newPrim.viewerFaces.Count;
            int numPrimFaces = newPrim.numPrimFaces;

            for (uint i = 0; i < numViewerFaces; i++)
            {
                PrimMesher.ViewerFace vf = newPrim.viewerFaces[(int)i];

                if (isSphere)
                {
                    vf.uv1.U = (vf.uv1.U - 0.5f) * 2.0f;
                    vf.uv2.U = (vf.uv2.U - 0.5f) * 2.0f;
                    vf.uv3.U = (vf.uv3.U - 0.5f) * 2.0f;
                }
            }
            if (m_shouldScale)
            {
                newPrim.Scale(prim.Scale.X, prim.Scale.Y, prim.Scale.Z);
            }

            // copy the vertex information into OMVR.IRendering structures
            OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh();
            omvrmesh.Faces = new List<OMVR.Face>();
            omvrmesh.Prim = prim;
            omvrmesh.Profile = new OMVR.Profile();
            omvrmesh.Profile.Faces = new List<OMVR.ProfileFace>();
            omvrmesh.Profile.Positions = new List<OMV.Vector3>();
            omvrmesh.Path = new OMVR.Path();
            omvrmesh.Path.Points = new List<OMVR.PathPoint>();

            Dictionary<OMV.Vector3, int> vertexAccount = new Dictionary<OMV.Vector3, int>();
            for (int ii = 0; ii < numPrimFaces; ii++)
            {
                OMVR.Face oface = new OMVR.Face();
                oface.Vertices = new List<OMVR.Vertex>();
                oface.Indices = new List<ushort>();
                oface.TextureFace = prim.Textures.GetFace((uint)ii);
                int faceVertices = 0;
                vertexAccount.Clear();
                OMV.Vector3 pos;
                int indx;
                OMVR.Vertex vert;
                foreach (PrimMesher.ViewerFace vface in newPrim.viewerFaces)
                {
                    if (vface.primFaceNumber == ii)
                    {
                        faceVertices++;
                        pos = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z);
                        if (vertexAccount.ContainsKey(pos))
                        {
                            // we aleady have this vertex in the list. Just point the index at it
                            oface.Indices.Add((ushort)vertexAccount[pos]);
                        }
                        else
                        {
                            // the vertex is not in the list. Add it and the new index.
                            vert = new OMVR.Vertex();
                            vert.Position = pos;
                            vert.TexCoord = new OMV.Vector2(vface.uv1.U, 1.0f - vface.uv1.V);
                            vert.Normal = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z);
                            oface.Vertices.Add(vert);
                            indx = oface.Vertices.Count - 1;
                            vertexAccount.Add(pos, indx);
                            oface.Indices.Add((ushort)indx);
                        }

                        pos = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z);
                        if (vertexAccount.ContainsKey(pos))
                        {
                            oface.Indices.Add((ushort)vertexAccount[pos]);
                        }
                        else
                        {
                            vert = new OMVR.Vertex();
                            vert.Position = pos;
                            vert.TexCoord = new OMV.Vector2(vface.uv2.U, 1.0f - vface.uv2.V);
                            vert.Normal = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z);
                            oface.Vertices.Add(vert);
                            indx = oface.Vertices.Count - 1;
                            vertexAccount.Add(pos, indx);
                            oface.Indices.Add((ushort)indx);
                        }

                        pos = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z);
                        if (vertexAccount.ContainsKey(pos))
                        {
                            oface.Indices.Add((ushort)vertexAccount[pos]);
                        }
                        else
                        {
                            vert = new OMVR.Vertex();
                            vert.Position = pos;
                            vert.TexCoord = new OMV.Vector2(vface.uv3.U, 1.0f - vface.uv3.V);
                            vert.Normal = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z);
                            oface.Vertices.Add(vert);
                            indx = oface.Vertices.Count - 1;
                            vertexAccount.Add(pos, indx);
                            oface.Indices.Add((ushort)indx);
                        }
                    }
                }
                if (faceVertices > 0)
                {
                    oface.TextureFace = prim.Textures.FaceTextures[ii];
                    if (oface.TextureFace == null)
                    {
                        oface.TextureFace = prim.Textures.DefaultTexture;
                    }
                    oface.ID = ii;
                    omvrmesh.Faces.Add(oface);
                }
            }

            return omvrmesh;
        }