public ExportResult Export(GroupDisplayData datas)
        {
            ExportStats stats = new ExportStats();
            BabylonFlatBufferOutputs outputs = new BabylonFlatBufferOutputs();
            string tempPath = Path.GetTempPath();

            var prims = new List <Mesh>();

            Tuple <string, Mesh, List <MeshInstance> > rootPrim = SerializeCombinedFaces(null, datas.RootPrim, "png", tempPath, outputs, stats);

            prims.Add(rootPrim.Item2);

            foreach (var data in datas.Prims.Where(p => p != datas.RootPrim))
            {
                prims.Add(SerializeCombinedFaces(rootPrim.Item1, data, "png", tempPath, outputs, stats).Item2);
            }

            var res = PackageResult(datas.ObjectName, datas.CreatorName, outputs, prims);

            stats.ConcreteCount = 1;
            stats.TextureCount  = res.TextureFiles.Count;
            res.Stats           = stats;
            res.Hash            = GetGroupHash(datas);

            return(res);
        }
        public ExportResult Export(PrimDisplayData data)
        {
            ExportStats stats = new ExportStats();
            BabylonFlatBufferOutputs outputs = new BabylonFlatBufferOutputs();
            string tempPath = Path.GetTempPath();

            Tuple <string, Mesh, List <MeshInstance> > result = SerializeCombinedFaces(null, data, "png", tempPath, outputs, stats);

            var res = PackageResult("object", "creator", outputs, new List <Mesh> {
                result.Item2
            });

            res.Stats           = stats;
            stats.ConcreteCount = 1;

            return(res);
        }
        public ExportResult Export(IEnumerable <GroupDisplayData> groups)
        {
            ExportStats stats = new ExportStats();
            BabylonFlatBufferOutputs outputs = new BabylonFlatBufferOutputs();
            string tempPath = Path.GetTempPath();

            var prims          = new List <Mesh>();
            var groupInstances = new Dictionary <ulong, List <MeshInstance> >();

            foreach (var group in groups)
            {
                //see if we already have this group
                ulong groupHash = GetGroupHash(group);

                List <MeshInstance> instances;
                if (groupInstances.TryGetValue(groupHash, out instances))
                {
                    var pos = group.RootPrim.OffsetPosition;
                    var rot = group.RootPrim.OffsetRotation;

                    FixCoordinateSystem(ref pos, ref rot);

                    //yes, add this as an instance of the group
                    outputs.Instances.Add(new MeshInstance()
                    {
                        Name     = groupHash + "_inst_" + instances.Count,
                        Position = pos,
                        Rotation = rot,
                        Scaling  = group.RootPrim.Scale
                    });

                    stats.InstanceCount++;
                }
                else
                {
                    int startingPrimCount    = stats.PrimCount;
                    int startingSubmeshCount = stats.SubmeshCount;

                    Tuple <string, Mesh, List <MeshInstance> > rootPrim = SerializeCombinedFaces(null, group.RootPrim, "png", tempPath, outputs, stats);
                    prims.Add(rootPrim.Item2);

                    foreach (var data in group.Prims.Where(p => p != group.RootPrim))
                    {
                        prims.Add(SerializeCombinedFaces(rootPrim.Item1, data, "png", tempPath, outputs, stats).Item2);
                    }

                    groupInstances.Add(groupHash, rootPrim.Item3);

                    stats.GroupsByPrimCount.Add(new Tuple <string, int>(group.ObjectName + "-" + groupHash, stats.PrimCount - startingPrimCount));
                    stats.GroupsBySubmeshCount.Add(new Tuple <string, int>(group.ObjectName + "-" + groupHash, stats.SubmeshCount - startingSubmeshCount));

                    stats.ConcreteCount++;
                }
            }


            var res = PackageResult(string.Empty, string.Empty, outputs, prims);

            stats.TextureCount = res.TextureFiles.Count;
            res.Stats          = stats;
            return(res);
        }
        /// <summary>
        /// Serializes the combined faces and returns a mesh
        /// </summary>
        private Tuple <string, Mesh, List <MeshInstance> > SerializeCombinedFaces(
            string parent, PrimDisplayData data,
            string materialType, string tempPath, BabylonFlatBufferOutputs outputs,
            ExportStats stats)
        {
            stats.PrimCount++;

            BabylonPrimFaceCombiner combiner = new BabylonPrimFaceCombiner();

            foreach (var face in data.Mesh.Faces)
            {
                combiner.CombineFace(face);
            }

            combiner.Complete();

            List <string> materialsList = new List <string>();

            for (int i = 0; i < combiner.Materials.Count; i++)
            {
                var   material     = combiner.Materials[i];
                float shinyPercent = ShinyToPercent(material.Shiny);

                bool hasTexture = material.TextureID != OpenMetaverse.UUID.Zero;

                //check the material tracker, if we already have this texture, don't export it again
                TrackedTexture trackedTexture = null;

                if (hasTexture)
                {
                    if (outputs.Textures.ContainsKey(material.TextureID))
                    {
                        trackedTexture = outputs.Textures[material.TextureID];
                    }
                    else
                    {
                        string materialMapName = $"tex_mat_{material.TextureID}.{materialType}";
                        var    kvp             = this.WriteMaterialTexture(material.TextureID, materialMapName, tempPath, outputs.TextureFiles);

                        outputs.Textures.Add(kvp.Key, kvp.Value);

                        trackedTexture = kvp.Value;
                    }
                }

                var matHash = _objHasher.GetMaterialFaceHash(material);
                if (!outputs.Materials.ContainsKey(matHash))
                {
                    bool hasTransparent = material.RGBA.A < 1.0f || (trackedTexture != null && trackedTexture.HasAlpha);

                    Texture texture = null;
                    if (hasTexture)
                    {
                        texture = new Texture()
                        {
                            HasAlpha = hasTransparent,
                            Name     = trackedTexture.Name
                        };
                    }

                    BabylonFlatBufferIntermediates.Material jsMaterial = new BabylonFlatBufferIntermediates.Material()
                    {
                        Alpha          = material.RGBA.A,
                        Color          = new[] { material.RGBA.R, material.RGBA.G, material.RGBA.B },
                        DiffuseTexture = hasTexture ? texture : null,
                        Id             = matHash.ToString(),
                        Name           = matHash.ToString(),
                        ShinyPercent   = shinyPercent
                    };

                    outputs.Materials.Add(matHash, jsMaterial);
                }

                materialsList.Add(matHash.ToString());
            }

            var multiMaterialName = data.MaterialHash + "_mm";

            if (!outputs.MultiMaterials.ContainsKey(data.MaterialHash))
            {
                //create the multimaterial
                var multiMaterial = new MultiMaterial()
                {
                    Id            = multiMaterialName,
                    MaterialsList = materialsList,
                    Name          = multiMaterialName
                };

                outputs.MultiMaterials[data.MaterialHash] = multiMaterial;
            }

            List <SubMesh> submeshes = new List <SubMesh>();

            foreach (var subMesh in combiner.SubMeshes)
            {
                submeshes.Add(new SubMesh()
                {
                    MaterialIndex = subMesh.MaterialIndex,
                    VerticesStart = subMesh.VerticesStart,
                    VerticesCount = subMesh.VerticesCount,
                    IndexStart    = subMesh.IndexStart,
                    IndexCount    = subMesh.IndexCount
                });

                stats.SubmeshCount++;
            }

            List <MeshInstance> instanceList = null;

            if (parent == null)
            {
                instanceList = new List <MeshInstance>();
            }

            //if this is a child prim, divide out the scale of the parent
            var scale = data.Scale;

            if (parent != null)
            {
                scale /= data.Parent.Scale;
            }

            Vector3    pos = data.OffsetPosition;
            Quaternion rot = data.OffsetRotation;

            if (parent == null)
            {
                FixCoordinateSystem(ref pos, ref rot);
            }


            var primId = data.ShapeHash + "_" + data.MaterialHash + (parent == null ? "_P" : "");

            Mesh mesh = new Mesh()
            {
                Name               = primId,
                Id                 = primId,
                ParentId           = parent,
                MaterialId         = multiMaterialName,
                Position           = new [] { pos.X, pos.Y, pos.Z },
                RotationQuaternion = new[] { rot.X, rot.Y, rot.Z, rot.W },
                Scaling            = new[] { scale.X, scale.Y, scale.Z },
                Positions          = combiner.Vertices,
                Normals            = combiner.Normals,
                UVs                = combiner.UVs,
                Indices            = combiner.Indices,
                Submeshes          = submeshes,
                Instances          = instanceList
            };

            return(new Tuple <string, Mesh, List <MeshInstance> >(primId, mesh, instanceList));
        }
        private static ExportResult PackageResult(string objectName, string creatorName, BabylonFlatBufferOutputs outputs, List <Mesh> prims)
        {
            ExportResult result = new ExportResult();

            result.ObjectName  = objectName;
            result.CreatorName = creatorName;

            FlatBufferBuilder builder = new FlatBufferBuilder(2048);

            List <Offset <BabylonFlatBuffers.Material> > materialOffsets = new List <Offset <Material> >();

            foreach (var mat in outputs.Materials.Values)
            {
                var id          = builder.CreateString(mat.Id);
                var name        = builder.CreateString(mat.Name);
                var color       = BabylonFlatBuffers.Material.CreateColorVector(builder, mat.Color);
                var textureName = builder.CreateString(mat.DiffuseTexture.Name);
                var texture     = BabylonFlatBuffers.Texture.CreateTexture(builder, textureName, mat.DiffuseTexture.HasAlpha);

                var outMat = BabylonFlatBuffers.Material.CreateMaterial(builder, id, name, color, mat.ShinyPercent,
                                                                        mat.Alpha, texture);
                materialOffsets.Add(outMat);
            }


            List <Offset <BabylonFlatBuffers.MultiMaterial> > multiMaterialOffsets = new List <Offset <BabylonFlatBuffers.MultiMaterial> >();

            foreach (var mat in outputs.MultiMaterials.Values)
            {
                var id   = builder.CreateString(mat.Id);
                var name = builder.CreateString(mat.Name);

                List <StringOffset> materialIds = new List <StringOffset>();
                foreach (var matId in mat.MaterialsList)
                {
                    materialIds.Add(builder.CreateString(matId));
                }

                var matList = BabylonFlatBuffers.MultiMaterial.CreateMaterialsListVector(builder, materialIds.ToArray());
                var outMat  = BabylonFlatBuffers.MultiMaterial.CreateMultiMaterial(builder, id, name, matList);
                multiMaterialOffsets.Add(outMat);
            }


            List <Offset <BabylonFlatBuffers.Mesh> > meshOffsets = new List <Offset <BabylonFlatBuffers.Mesh> >();

            foreach (var mesh in prims)
            {
                var id                 = builder.CreateString(mesh.Id);
                var name               = builder.CreateString(mesh.Name);
                var parentId           = builder.CreateString(mesh.ParentId);
                var materialId         = builder.CreateString(mesh.MaterialId);
                var position           = BabylonFlatBuffers.Mesh.CreatePositionVector(builder, mesh.Position);
                var rotationQuaternion = BabylonFlatBuffers.Mesh.CreateRotationQuaternionVector(builder,
                                                                                                mesh.RotationQuaternion);
                var scaling   = BabylonFlatBuffers.Mesh.CreateScalingVector(builder, mesh.Scaling);
                var positions = BabylonFlatBuffers.Mesh.CreatePositionsVector(builder, mesh.Positions.ToArray());
                var normals   = BabylonFlatBuffers.Mesh.CreateNormalsVector(builder, mesh.Normals.ToArray());
                var uvs       = BabylonFlatBuffers.Mesh.CreateUvsVector(builder, mesh.UVs.ToArray());
                var indices   = BabylonFlatBuffers.Mesh.CreateIndicesVector(builder, mesh.Indices.ToArray());

                var submeshList = new List <Offset <BabylonFlatBuffers.SubMesh> >();
                foreach (var submesh in mesh.Submeshes)
                {
                    var submeshOff = BabylonFlatBuffers.SubMesh.CreateSubMesh(builder, submesh.MaterialIndex,
                                                                              submesh.VerticesStart, submesh.VerticesCount, submesh.IndexStart, submesh.IndexCount);
                    submeshList.Add(submeshOff);
                }

                var submeshes = BabylonFlatBuffers.Mesh.CreateSubmeshesVector(builder, submeshList.ToArray());

                var outMesh = BabylonFlatBuffers.Mesh.CreateMesh(builder, id, name, parentId, materialId,
                                                                 position, rotationQuaternion, scaling, positions, normals, uvs, indices, submeshes);

                meshOffsets.Add(outMesh);
            }

            var materialsVector      = BabylonFlatBuffers.BabylonFileFlatbuffer.CreateMaterialsVector(builder, materialOffsets.ToArray());
            var multiMaterialsVector = BabylonFlatBuffers.BabylonFileFlatbuffer.CreateMultiMaterialsVector(builder, multiMaterialOffsets.ToArray());
            var meshesVector         = BabylonFlatBuffers.BabylonFileFlatbuffer.CreateMeshesVector(builder,
                                                                                                   meshOffsets.ToArray());

            var offset = BabylonFlatBuffers.BabylonFileFlatbuffer.CreateBabylonFileFlatbuffer(builder, materialsVector,
                                                                                              multiMaterialsVector, meshesVector);


            BabylonFlatBuffers.BabylonFileFlatbuffer.FinishBabylonFileFlatbufferBuffer(builder, offset);
            result.FaceBlob = new Tuple <byte[], int, int>(builder.DataBuffer.Data, builder.DataBuffer.Position, builder.DataBuffer.Length);

            return(result);
        }