コード例 #1
0
ファイル: FBXTestGame.cs プロジェクト: yongweisun/paradox
        protected override async Task LoadContent()
        {
            await base.LoadContent();

            // Create Main pass
            var mainPipeline = RenderSystem.Pipeline;

            mainPipeline.Renderers.Add(new RenderTargetSetter(Services)
            {
                ClearColor = Color.Blue, RenderTarget = GraphicsDevice.BackBuffer, DepthStencil = GraphicsDevice.DepthStencilBuffer
            });
            mainPipeline.Renderers.Add(new ModelRenderer(Services, "Default"));

            // Setup view
            var renderPipeline = RenderSystem.Pipeline;

            renderPipeline.Parameters.Set(TransformationKeys.View, Matrix.LookAtLH(new Vector3(100.0f, 80.0f, 100.0f), new Vector3(0.0f, 0.0f, 0.0f), Vector3.UnitZ));
            renderPipeline.Parameters.Set(TransformationKeys.Projection, Matrix.PerspectiveFovLH((float)Math.PI * 0.4f, 1.3f, 1.0f, 1000.0f));

            // Load asset
            var sceneModel = Asset.Load <Model>("factory_model");

            // Create render model with main pipeline
            renderModel = new RenderModel(mainPipeline, sceneModel);
            mvh         = new ModelViewHierarchyUpdater(sceneModel);
        }
コード例 #2
0
 private void ModelUpdated()
 {
     if (model != null)
     {
         if (modelViewHierarchy != null)
         {
             // Reuse previous ModelViewHierarchy
             modelViewHierarchy.Initialize(model);
         }
         else
         {
             modelViewHierarchy = new ModelViewHierarchyUpdater(model);
         }
     }
 }
コード例 #3
0
        /// <inheritdoc/>
        public override void ComputeMatrix(bool recursive, out Matrix matrix)
        {
            // If model is not in the parent, we might want to force recursive update (since parentModelComponent might not be updated yet)
            if (forceRecursive || recursive)
            {
                parentModelComponent.Entity.Transform.UpdateWorldMatrix();
            }

            // Updated? (rare slow path)
            if (parentModelComponent.ModelViewHierarchy != modelViewHierarchy)
            {
                modelViewHierarchy = parentModelComponent.ModelViewHierarchy;
                if (modelViewHierarchy == null)
                {
                    goto failed;
                }

                // Find our node index
                nodeIndex = int.MaxValue;
                for (int index = 0; index < modelViewHierarchy.Nodes.Length; index++)
                {
                    var node = modelViewHierarchy.Nodes[index];
                    if (node.Name == nodeName)
                    {
                        nodeIndex = index;
                    }
                }
            }

            var nodes = modelViewHierarchy.Nodes;
            var nodeTransformations = modelViewHierarchy.NodeTransformations;

            if (nodeIndex >= nodes.Length)
            {
                goto failed;
            }

            // Hopefully, if ref locals gets merged in roslyn, this code can be refactored
            // Compute
            matrix = nodeTransformations[nodeIndex].WorldMatrix;
            return;

failed:
            // Fallback to TransformComponent
            matrix = parentModelComponent.Entity.Transform.WorldMatrix;
            return;
        }
コード例 #4
0
ファイル: ImportModelCommand.cs プロジェクト: dhootha/paradox
        /// <summary>
        /// Get the transformation matrix to go from rootIndex to index.
        /// </summary>
        /// <param name="hierarchy">The node hierarchy.</param>
        /// <param name="updater">The updater containing the local matrices.</param>
        /// <param name="rootIndex">The root index.</param>
        /// <param name="index">The current index.</param>
        /// <returns>The matrix at this index.</returns>
        private Matrix GetMatrixFromIndex(ModelNodeDefinition[] hierarchy, ModelViewHierarchyUpdater updater, int rootIndex, int index)
        {
            if (index == -1 || index == rootIndex)
            {
                return(Matrix.Identity);
            }

            Matrix outMatrix;

            updater.GetLocalMatrix(index, out outMatrix);

            if (index != rootIndex)
            {
                var topMatrix = GetMatrixFromIndex(hierarchy, updater, rootIndex, hierarchy[index].ParentIndex);
                outMatrix = Matrix.Multiply(outMatrix, topMatrix);
            }

            return(outMatrix);
        }
コード例 #5
0
ファイル: ImportModelCommand.cs プロジェクト: dhootha/paradox
        /// <summary>
        /// The method to override containing the actual command code. It is called by the <see cref="DoCommand" /> function
        /// </summary>
        /// <param name="commandContext">The command context.</param>
        /// <returns>Task{ResultStatus}.</returns>
        protected override async Task <ResultStatus> DoCommandOverride(ICommandContext commandContext)
        {
            var assetManager = new AssetManager();

            while (Interlocked.Increment(ref spawnedFbxCommands) >= 2)
            {
                Interlocked.Decrement(ref spawnedFbxCommands);
                await Task.Delay(1, CancellationToken);
            }

            try
            {
                object exportedObject;

                if (ExportType == "animation")
                {
                    // Read from model file
                    var animationClip = LoadAnimation(commandContext, assetManager);
                    exportedObject = animationClip;
                    if (animationClip == null)
                    {
                        commandContext.Logger.Info("File {0} has an empty animation.", SourcePath);
                    }
                    else if (animationClip.Duration.Ticks == 0)
                    {
                        commandContext.Logger.Warning("File {0} has a 0 tick long animation.", SourcePath);
                    }
                    else
                    {
                        animationClip.RepeatMode = AnimationRepeatMode;
                        animationClip.Optimize();
                    }
                }
                else if (ExportType == "model")
                {
                    // Read from model file
                    var model = LoadModel(commandContext, assetManager);

                    // Apply materials
                    foreach (var modelMaterial in Materials)
                    {
                        if (modelMaterial.MaterialInstance == null || modelMaterial.MaterialInstance.Material == null)
                        {
                            commandContext.Logger.Warning(string.Format("The material [{0}] is null in the list of materials.", modelMaterial.Name));
                            continue;
                        }
                        model.Materials.Add(modelMaterial.MaterialInstance);
                    }

                    model.BoundingBox = BoundingBox.Empty;
                    var hierarchyUpdater = new ModelViewHierarchyUpdater(model.Hierarchy.Nodes);
                    hierarchyUpdater.UpdateMatrices();

                    bool hasErrors = false;
                    foreach (var mesh in model.Meshes)
                    {
                        if (TessellationAEN)
                        {
                            // TODO: Generate AEN model view
                            commandContext.Logger.Error("TessellationAEN is not supported in {0}", ContextAsString);
                            hasErrors = true;
                        }
                    }

                    // split the meshes if necessary
                    model.Meshes = SplitExtensions.SplitMeshes(model.Meshes, Allow32BitIndex);

                    // merge the meshes
                    if (Compact)
                    {
                        var indicesBlackList = new HashSet <int>();
                        if (PreservedNodes != null)
                        {
                            for (var index = 0; index < model.Hierarchy.Nodes.Length; ++index)
                            {
                                var node = model.Hierarchy.Nodes[index];
                                if (PreservedNodes.Contains(node.Name))
                                {
                                    indicesBlackList.Add(index);
                                }
                            }
                        }

                        // group meshes with same material and same root
                        var sameMaterialMeshes = new List <GroupList <int, Mesh> >();
                        GroupFromIndex(model, 0, indicesBlackList, model.Meshes, sameMaterialMeshes);

                        // remove meshes that cannot be merged
                        var excludedMeshes  = new List <Mesh>();
                        var finalMeshGroups = new List <GroupList <int, Mesh> >();
                        foreach (var meshList in sameMaterialMeshes)
                        {
                            var mergeList = new GroupList <int, Mesh> {
                                Key = meshList.Key
                            };

                            foreach (var mesh in meshList)
                            {
                                if (mesh.Skinning != null || indicesBlackList.Contains(mesh.NodeIndex))
                                {
                                    excludedMeshes.Add(mesh);
                                }
                                else
                                {
                                    mergeList.Add(mesh);
                                }
                            }

                            if (mergeList.Count <= 1)
                            {
                                excludedMeshes.AddRange(mergeList);
                            }
                            else
                            {
                                finalMeshGroups.Add(mergeList);
                            }
                        }

                        var finalMeshes = new List <Mesh>();

                        finalMeshes.AddRange(excludedMeshes);

                        foreach (var meshList in finalMeshGroups)
                        {
                            // transform the buffers
                            foreach (var mesh in meshList)
                            {
                                var transformationMatrix = GetMatrixFromIndex(model.Hierarchy.Nodes, hierarchyUpdater, meshList.Key, mesh.NodeIndex);
                                mesh.Draw.VertexBuffers[0].TransformBuffer(ref transformationMatrix);
                            }

                            // refine the groups base on several tests
                            var newMeshGroups = new List <GroupList <int, Mesh> > {
                                meshList
                            };
                            // only regroup meshes if they share the same parameters
                            newMeshGroups = RefineGroups(model, newMeshGroups, CompareParameters);

                            // only regroup meshes if they share the shadow options
                            newMeshGroups = RefineGroups(model, newMeshGroups, CompareShadowOptions);

                            // add to the final meshes groups
                            foreach (var sameParamsMeshes in newMeshGroups)
                            {
                                var baseMesh    = sameParamsMeshes[0];
                                var newMeshList = sameParamsMeshes.Select(x => x.Draw).ToList().GroupDrawData(Allow32BitIndex);
                                foreach (var generatedMesh in newMeshList)
                                {
                                    finalMeshes.Add(new Mesh(generatedMesh, baseMesh.Parameters)
                                    {
                                        MaterialIndex = baseMesh.MaterialIndex,
                                        Name          = baseMesh.Name,
                                        Draw          = generatedMesh,
                                        NodeIndex     = meshList.Key,
                                        Skinning      = null,
                                    });
                                }
                            }
                        }

                        // delete empty nodes (neither mesh nor bone attached)
                        var keptNodes = new bool[model.Hierarchy.Nodes.Length];
                        for (var i = 0; i < keptNodes.Length; ++i)
                        {
                            keptNodes[i] = false;
                        }
                        foreach (var keepIndex in indicesBlackList)
                        {
                            var nodeIndex = keepIndex;
                            while (nodeIndex != -1 && !keptNodes[nodeIndex])
                            {
                                keptNodes[nodeIndex] = true;
                                nodeIndex            = model.Hierarchy.Nodes[nodeIndex].ParentIndex;
                            }
                        }
                        foreach (var mesh in finalMeshes)
                        {
                            var nodeIndex = mesh.NodeIndex;
                            while (nodeIndex != -1 && !keptNodes[nodeIndex])
                            {
                                keptNodes[nodeIndex] = true;
                                nodeIndex            = model.Hierarchy.Nodes[nodeIndex].ParentIndex;
                            }

                            if (mesh.Skinning != null)
                            {
                                foreach (var bone in mesh.Skinning.Bones)
                                {
                                    nodeIndex = bone.NodeIndex;
                                    while (nodeIndex != -1 && !keptNodes[nodeIndex])
                                    {
                                        keptNodes[nodeIndex] = true;
                                        nodeIndex            = model.Hierarchy.Nodes[nodeIndex].ParentIndex;
                                    }
                                }
                            }
                        }

                        var newNodes   = new List <ModelNodeDefinition>();
                        var newMapping = new int[model.Hierarchy.Nodes.Length];
                        for (var i = 0; i < keptNodes.Length; ++i)
                        {
                            if (keptNodes[i])
                            {
                                var parentIndex = model.Hierarchy.Nodes[i].ParentIndex;
                                if (parentIndex != -1)
                                {
                                    model.Hierarchy.Nodes[i].ParentIndex = newMapping[parentIndex]; // assume that the nodes are well ordered
                                }
                                newMapping[i] = newNodes.Count;
                                newNodes.Add(model.Hierarchy.Nodes[i]);
                            }
                        }

                        foreach (var mesh in finalMeshes)
                        {
                            mesh.NodeIndex = newMapping[mesh.NodeIndex];

                            if (mesh.Skinning != null)
                            {
                                for (var i = 0; i < mesh.Skinning.Bones.Length; ++i)
                                {
                                    mesh.Skinning.Bones[i].NodeIndex = newMapping[mesh.Skinning.Bones[i].NodeIndex];
                                }
                            }
                        }

                        model.Meshes          = finalMeshes;
                        model.Hierarchy.Nodes = newNodes.ToArray();

                        hierarchyUpdater = new ModelViewHierarchyUpdater(model.Hierarchy.Nodes);
                        hierarchyUpdater.UpdateMatrices();
                    }

                    // bounding boxes
                    var modelBoundingBox    = model.BoundingBox;
                    var modelBoundingSphere = model.BoundingSphere;
                    foreach (var mesh in model.Meshes)
                    {
                        var vertexBuffers = mesh.Draw.VertexBuffers;
                        if (vertexBuffers.Length > 0)
                        {
                            // Compute local mesh bounding box (no node transformation)
                            Matrix matrix = Matrix.Identity;
                            mesh.BoundingBox = vertexBuffers[0].ComputeBounds(ref matrix, out mesh.BoundingSphere);

                            // Compute model bounding box (includes node transformation)
                            hierarchyUpdater.GetWorldMatrix(mesh.NodeIndex, out matrix);
                            BoundingSphere meshBoundingSphere;
                            var            meshBoundingBox = vertexBuffers[0].ComputeBounds(ref matrix, out meshBoundingSphere);
                            BoundingBox.Merge(ref modelBoundingBox, ref meshBoundingBox, out modelBoundingBox);
                            BoundingSphere.Merge(ref modelBoundingSphere, ref meshBoundingSphere, out modelBoundingSphere);
                        }

                        // TODO: temporary Always try to compact
                        mesh.Draw.CompactIndexBuffer();
                    }
                    model.BoundingBox    = modelBoundingBox;
                    model.BoundingSphere = modelBoundingSphere;

                    // merges all the Draw VB and IB together to produce one final VB and IB by entity.
                    var sizeVertexBuffer = model.Meshes.SelectMany(x => x.Draw.VertexBuffers).Select(x => x.Buffer.GetSerializationData().Content.Length).Sum();
                    var sizeIndexBuffer  = 0;
                    foreach (var x in model.Meshes)
                    {
                        // Let's be aligned (if there was 16bit indices before, we might be off)
                        if (x.Draw.IndexBuffer.Is32Bit && sizeIndexBuffer % 4 != 0)
                        {
                            sizeIndexBuffer += 2;
                        }

                        sizeIndexBuffer += x.Draw.IndexBuffer.Buffer.GetSerializationData().Content.Length;
                    }
                    var vertexBuffer = new BufferData(BufferFlags.VertexBuffer, new byte[sizeVertexBuffer]);
                    var indexBuffer  = new BufferData(BufferFlags.IndexBuffer, new byte[sizeIndexBuffer]);

                    // Note: reusing same instance, to avoid having many VB with same hash but different URL
                    var vertexBufferSerializable = vertexBuffer.ToSerializableVersion();
                    var indexBufferSerializable  = indexBuffer.ToSerializableVersion();

                    var vertexBufferNextIndex = 0;
                    var indexBufferNextIndex  = 0;
                    foreach (var drawMesh in model.Meshes.Select(x => x.Draw))
                    {
                        // the index buffer
                        var oldIndexBuffer = drawMesh.IndexBuffer.Buffer.GetSerializationData().Content;

                        // Let's be aligned (if there was 16bit indices before, we might be off)
                        if (drawMesh.IndexBuffer.Is32Bit && indexBufferNextIndex % 4 != 0)
                        {
                            indexBufferNextIndex += 2;
                        }

                        Array.Copy(oldIndexBuffer, 0, indexBuffer.Content, indexBufferNextIndex, oldIndexBuffer.Length);

                        drawMesh.IndexBuffer = new IndexBufferBinding(indexBufferSerializable, drawMesh.IndexBuffer.Is32Bit, drawMesh.IndexBuffer.Count, indexBufferNextIndex);

                        indexBufferNextIndex += oldIndexBuffer.Length;

                        // the vertex buffers
                        for (int index = 0; index < drawMesh.VertexBuffers.Length; index++)
                        {
                            var vertexBufferBinding = drawMesh.VertexBuffers[index];
                            var oldVertexBuffer     = vertexBufferBinding.Buffer.GetSerializationData().Content;

                            Array.Copy(oldVertexBuffer, 0, vertexBuffer.Content, vertexBufferNextIndex, oldVertexBuffer.Length);

                            drawMesh.VertexBuffers[index] = new VertexBufferBinding(vertexBufferSerializable, vertexBufferBinding.Declaration, vertexBufferBinding.Count, vertexBufferBinding.Stride, vertexBufferNextIndex);

                            vertexBufferNextIndex += oldVertexBuffer.Length;
                        }
                    }


                    // If there were any errors while importing models
                    if (hasErrors)
                    {
                        return(ResultStatus.Failed);
                    }

                    // Convert to Entity
                    exportedObject = model;
                }
                else
                {
                    commandContext.Logger.Error("Unknown export type [{0}] {1}", ExportType, ContextAsString);
                    return(ResultStatus.Failed);
                }

                if (exportedObject != null)
                {
                    assetManager.Save(Location, exportedObject);
                }

                commandContext.Logger.Info("The {0} has been successfully imported.", ContextAsString);

                return(ResultStatus.Successful);
            }
            catch (Exception ex)
            {
                commandContext.Logger.Error("Unexpected error while importing {0}", ex, ContextAsString);
                return(ResultStatus.Failed);
            }
            finally
            {
                Interlocked.Decrement(ref spawnedFbxCommands);
            }
        }
コード例 #6
0
        protected override async Task <ResultStatus> DoCommandOverride(ICommandContext commandContext)
        {
            var assetManager = new AssetManager();

            while (Interlocked.Increment(ref spawnedFbxCommands) >= 2)
            {
                Interlocked.Decrement(ref spawnedFbxCommands);
                await Task.Delay(1, CancellationToken);
            }

            try
            {
                object exportedObject;

                if (ExportType == "animation")
                {
                    // Read from model file
                    var animationClip = LoadAnimation(commandContext, assetManager);
                    exportedObject = animationClip;
                    if (animationClip == null)
                    {
                        commandContext.Logger.Info("File {0} has an empty animation.", SourcePath);
                    }
                    else if (animationClip.Duration.Ticks == 0)
                    {
                        commandContext.Logger.Warning("File {0} has a 0 tick long animation.", SourcePath);
                    }
                    else
                    {
                        animationClip.RepeatMode = AnimationRepeatMode;
                        animationClip.Optimize();
                    }
                }
                else if (ExportType == "model")
                {
                    // Read from model file
                    var model = LoadModel(commandContext, assetManager);

                    model.BoundingBox = BoundingBox.Empty;
                    var hierarchyUpdater = new ModelViewHierarchyUpdater(model.Hierarchy.Nodes);
                    hierarchyUpdater.UpdateMatrices();

                    bool hasErrors = false;
                    foreach (var mesh in model.Meshes)
                    {
                        if (TessellationAEN)
                        {
                            // TODO: Generate AEN model view
                            commandContext.Logger.Error("TessellationAEN is not supported in {0}", ContextAsString);
                            hasErrors = true;
                            continue;
                        }

                        if (!Materials.ContainsKey(mesh.Name))
                        {
                            commandContext.Logger.Error("Mesh material [{0}] was not found in {1}", mesh.Name, ContextAsString);
                            hasErrors = true;
                            continue;
                        }

                        // set the material
                        var materialReference = Materials[mesh.Name];
                        mesh.Material = new ContentReference <MaterialData>(materialReference.Item1, materialReference.Item2);

                        // set the parameters
                        if (Parameters.ContainsKey(mesh.Name) && Parameters[mesh.Name] != null)
                        {
                            if (mesh.Parameters == null)
                            {
                                mesh.Parameters = new ParameterCollectionData();
                            }
                            foreach (var keyValue in Parameters[mesh.Name])
                            {
                                mesh.Parameters.Set(keyValue.Key, keyValue.Value);
                            }
                        }

                        // TODO: remove this when Lighting configuration will be behind a key in mesh parameters. This case will be handled by the code just above
                        // set the lighting configuration description
                        Tuple <Guid, string> lightingReference;
                        if (Lightings.TryGetValue(mesh.Name, out lightingReference))
                        {
                            mesh.Parameters.Set(LightingKeys.LightingConfigurations, new ContentReference <LightingConfigurationsSetData>(lightingReference.Item1, lightingReference.Item2));
                        }
                    }

                    // split the meshes if necessary
                    model.Meshes = SplitExtensions.SplitMeshes(model.Meshes, Allow32BitIndex);

                    // merge the meshes
                    if (Compact)
                    {
                        var indicesBlackList = new HashSet <int>();
                        if (PreservedNodes != null)
                        {
                            for (var index = 0; index < model.Hierarchy.Nodes.Length; ++index)
                            {
                                var node = model.Hierarchy.Nodes[index];
                                if (PreservedNodes.Contains(node.Name))
                                {
                                    indicesBlackList.Add(index);
                                }
                            }
                        }

                        // group meshes with same material and same root
                        var sameMaterialMeshes = new List <GroupList <int, MeshData> >();
                        GroupFromIndex(model, 0, indicesBlackList, model.Meshes, sameMaterialMeshes);

                        // remove meshes that cannot be merged
                        var excludedMeshes  = new List <MeshData>();
                        var finalMeshGroups = new List <GroupList <int, MeshData> >();
                        foreach (var meshList in sameMaterialMeshes)
                        {
                            var mergeList = new GroupList <int, MeshData> {
                                Key = meshList.Key
                            };

                            foreach (var mesh in meshList)
                            {
                                if (mesh.Skinning != null || indicesBlackList.Contains(mesh.NodeIndex))
                                {
                                    excludedMeshes.Add(mesh);
                                }
                                else
                                {
                                    mergeList.Add(mesh);
                                }
                            }

                            if (mergeList.Count <= 1)
                            {
                                excludedMeshes.AddRange(mergeList);
                            }
                            else
                            {
                                finalMeshGroups.Add(mergeList);
                            }
                        }

                        var finalMeshes = new List <MeshData>();

                        finalMeshes.AddRange(excludedMeshes);

                        foreach (var meshList in finalMeshGroups)
                        {
                            // transform the buffers
                            foreach (var mesh in meshList)
                            {
                                var transformationMatrix = GetMatrixFromIndex(model.Hierarchy.Nodes, hierarchyUpdater, meshList.Key, mesh.NodeIndex);
                                mesh.Draw.VertexBuffers[0].TransformBuffer(ref transformationMatrix);
                            }

                            // refine the groups base on several tests
                            var newMeshGroups = new List <GroupList <int, MeshData> > {
                                meshList
                            };
                            // only regroup meshes if they share the same parameters
                            newMeshGroups = RefineGroups(newMeshGroups, CompareParameters);
                            // only regroup meshes if they share the shadow options
                            newMeshGroups = RefineGroups(newMeshGroups, CompareShadowOptions);
                            //only regroup meshes if they share the same lighting configurations
                            newMeshGroups = RefineGroups(newMeshGroups, CompareLightingConfigurations);


                            // add to the final meshes groups
                            foreach (var sameParamsMeshes in newMeshGroups)
                            {
                                var baseMesh    = sameParamsMeshes[0];
                                var newMeshList = sameParamsMeshes.Select(x => x.Draw).ToList().GroupDrawData(Allow32BitIndex);
                                foreach (var generatedMesh in newMeshList)
                                {
                                    finalMeshes.Add(new MeshData {
                                        Material   = baseMesh.Material,
                                        Parameters = baseMesh.Parameters,
                                        Name       = baseMesh.Name,
                                        Draw       = generatedMesh,
                                        NodeIndex  = meshList.Key,
                                        Skinning   = null,
                                    });
                                }
                            }
                        }

                        // delete empty nodes (neither mesh nor bone attached)
                        var keptNodes = new bool[model.Hierarchy.Nodes.Length];
                        for (var i = 0; i < keptNodes.Length; ++i)
                        {
                            keptNodes[i] = false;
                        }
                        foreach (var keepIndex in indicesBlackList)
                        {
                            var nodeIndex = keepIndex;
                            while (nodeIndex != -1 && !keptNodes[nodeIndex])
                            {
                                keptNodes[nodeIndex] = true;
                                nodeIndex            = model.Hierarchy.Nodes[nodeIndex].ParentIndex;
                            }
                        }
                        foreach (var mesh in finalMeshes)
                        {
                            var nodeIndex = mesh.NodeIndex;
                            while (nodeIndex != -1 && !keptNodes[nodeIndex])
                            {
                                keptNodes[nodeIndex] = true;
                                nodeIndex            = model.Hierarchy.Nodes[nodeIndex].ParentIndex;
                            }

                            if (mesh.Skinning != null)
                            {
                                foreach (var bone in mesh.Skinning.Bones)
                                {
                                    nodeIndex = bone.NodeIndex;
                                    while (nodeIndex != -1 && !keptNodes[nodeIndex])
                                    {
                                        keptNodes[nodeIndex] = true;
                                        nodeIndex            = model.Hierarchy.Nodes[nodeIndex].ParentIndex;
                                    }
                                }
                            }
                        }

                        var newNodes   = new List <ModelNodeDefinition>();
                        var newMapping = new int[model.Hierarchy.Nodes.Length];
                        for (var i = 0; i < keptNodes.Length; ++i)
                        {
                            if (keptNodes[i])
                            {
                                var parentIndex = model.Hierarchy.Nodes[i].ParentIndex;
                                if (parentIndex != -1)
                                {
                                    model.Hierarchy.Nodes[i].ParentIndex = newMapping[parentIndex]; // assume that the nodes are well ordered
                                }
                                newMapping[i] = newNodes.Count;
                                newNodes.Add(model.Hierarchy.Nodes[i]);
                            }
                        }

                        foreach (var mesh in finalMeshes)
                        {
                            mesh.NodeIndex = newMapping[mesh.NodeIndex];

                            if (mesh.Skinning != null)
                            {
                                for (var i = 0; i < mesh.Skinning.Bones.Length; ++i)
                                {
                                    mesh.Skinning.Bones[i].NodeIndex = newMapping[mesh.Skinning.Bones[i].NodeIndex];
                                }
                            }
                        }

                        model.Meshes          = finalMeshes;
                        model.Hierarchy.Nodes = newNodes.ToArray();

                        hierarchyUpdater = new ModelViewHierarchyUpdater(model.Hierarchy.Nodes);
                        hierarchyUpdater.UpdateMatrices();
                    }

                    // bounding boxes
                    foreach (var mesh in model.Meshes)
                    {
                        var vertexBuffers = mesh.Draw.VertexBuffers;
                        if (vertexBuffers.Length > 0)
                        {
                            // Compute local mesh bounding box (no node transformation)
                            Matrix matrix = Matrix.Identity;
                            mesh.BoundingBox = vertexBuffers[0].ComputeBoundingBox(ref matrix);

                            // Compute model bounding box (includes node transformation)
                            hierarchyUpdater.GetWorldMatrix(mesh.NodeIndex, out matrix);
                            var meshBoundingBox = vertexBuffers[0].ComputeBoundingBox(ref matrix);
                            BoundingBox.Merge(ref model.BoundingBox, ref meshBoundingBox, out model.BoundingBox);
                        }

                        // TODO: temporary Always try to compact
                        mesh.Draw.CompactIndexBuffer();
                    }

                    // merges all the Draw VB and IB together to produce one final VB and IB by entity.
                    var sizeVertexBuffer      = model.Meshes.SelectMany(x => x.Draw.VertexBuffers).Select(x => x.Buffer.Value.Content.Length).Sum();
                    var sizeIndexBuffer       = model.Meshes.Select(x => x.Draw.IndexBuffer).Select(x => x.Buffer.Value.Content.Length).Sum();
                    var vertexBuffer          = new BufferData(BufferFlags.VertexBuffer, new byte[sizeVertexBuffer]);
                    var indexBuffer           = new BufferData(BufferFlags.IndexBuffer, new byte[sizeIndexBuffer]);
                    var vertexBufferNextIndex = 0;
                    var indexBufferNextIndex  = 0;
                    foreach (var drawMesh in model.Meshes.Select(x => x.Draw))
                    {
                        // the index buffer
                        var oldIndexBuffer = drawMesh.IndexBuffer.Buffer.Value.Content;

                        Array.Copy(oldIndexBuffer, 0, indexBuffer.Content, indexBufferNextIndex, oldIndexBuffer.Length);

                        drawMesh.IndexBuffer.Offset = indexBufferNextIndex;
                        drawMesh.IndexBuffer.Buffer = indexBuffer;

                        indexBufferNextIndex += oldIndexBuffer.Length;

                        // the vertex buffers
                        foreach (var vertexBufferBinding in drawMesh.VertexBuffers)
                        {
                            var oldVertexBuffer = vertexBufferBinding.Buffer.Value.Content;

                            Array.Copy(oldVertexBuffer, 0, vertexBuffer.Content, vertexBufferNextIndex, oldVertexBuffer.Length);

                            vertexBufferBinding.Offset = vertexBufferNextIndex;
                            vertexBufferBinding.Buffer = vertexBuffer;

                            vertexBufferNextIndex += oldVertexBuffer.Length;
                        }
                    }


                    // If there were any errors while importing models
                    if (hasErrors)
                    {
                        return(ResultStatus.Failed);
                    }

                    // Convert to Entity
                    exportedObject = model;
                }
                else
                {
                    commandContext.Logger.Error("Unknown export type [{0}] {1}", ExportType, ContextAsString);
                    return(ResultStatus.Failed);
                }

                if (exportedObject != null)
                {
                    assetManager.Save(Location, exportedObject);
                }

                commandContext.Logger.Info("The {0} has been successfully imported.", ContextAsString);

                return(ResultStatus.Successful);
            }
            catch (Exception ex)
            {
                commandContext.Logger.Error("Unexpected error while importing {0}", ex, ContextAsString);
                return(ResultStatus.Failed);
            }
            finally
            {
                Interlocked.Decrement(ref spawnedFbxCommands);
            }
        }