private void sceneView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            // ignore parent nodes as they are just containers for the mesh nodes
            if (sceneView.SelectedNode.Nodes.Count > 0)
            {
                return;
            }

            if (sceneView.SelectedNode != null)
            {
                rotateModeBtn.Enabled    = true;
                translateModeBtn.Enabled = true;

                exportMeshButton.Enabled = true;

                RenderTreeNode rn      = (RenderTreeNode)sceneView.SelectedNode;
                RenderMessage  message = new RenderMessage(MessageType.SELECT_NODE, rn.MeshNode);
                commandQueue.Enqueue(message);
            }
            else
            {
                rotateModeBtn.Enabled    = false;
                translateModeBtn.Enabled = false;

                exportMeshButton.Enabled = false;
                RenderMessage message = new RenderMessage(MessageType.DESELECT_NODE);
                commandQueue.Enqueue(message);
            }
        }
        private void ExportNode(RenderTreeNode node, string exportMeshDirectory, string modelExtension, string texExtension, bool transformToWorld, string instanceName)
        {
            string meshNameOnly = Path.GetFileNameWithoutExtension(node.FullPath);
            string filename     = exportMeshDirectory + "\\" + meshNameOnly + instanceName + modelExtension;

            // export textures too!
            if (node.MeshNode.GetType().Equals(typeof(MeshSceneNode)))
            {
                MeshSceneNode meshNode = (MeshSceneNode)node.MeshNode;
                foreach (var mb in meshNode.Mesh.MeshBuffers)
                {
                    if (mb.Material.GetTexture(0) != null)
                    {
                        string tname = mb.Material.GetTexture(0).Name.ToString();
                        tname = tname.Replace(".xbm", texExtension);
                        tname = exportMeshDirectory + "\\" + Path.GetFileName(tname);

                        ExportTexture(tname, mb.Material.GetTexture(0));
                    }

                    if (mb.Material.GetTexture(1) != null)
                    {
                        string tname = mb.Material.GetTexture(1).Name.ToString();
                        tname = tname.Replace(".xbm", texExtension);
                        tname = exportMeshDirectory + "\\" + Path.GetFileName(tname);

                        ExportTexture(tname, mb.Material.GetTexture(1));
                    }
                }
            }

            if (modelExtension == ".obj")
            {
                var mw = smgr.CreateMeshWriter(MeshWriterType.Obj);
                if (transformToWorld)
                {
                    Matrix localToWorld = new Matrix(node.MeshNode.Position, node.MeshNode.Rotation);
                    mw.SetTransform(localToWorld);
                }
                mw.SetImageType(texExtension);
                if (node.MeshNode.GetType().Equals(typeof(MeshSceneNode)))
                {
                    mw.WriteMesh(device.FileSystem.CreateWriteFile(filename), ((MeshSceneNode)(node.MeshNode)).Mesh, MeshWriterFlag.None);
                }
                else
                {
                    mw.WriteMesh(device.FileSystem.CreateWriteFile(filename), ((TerrainSceneNodeWolvenKit)(node.MeshNode)).Mesh, MeshWriterFlag.None);
                }
                mw.Drop();
            }
            else if (modelExtension == ".fbx")
            {
                var mw = smgr.CreateMeshWriter(MeshWriterType.Fbx);
                if (transformToWorld)
                {
                    Matrix localToWorld = new Matrix(node.MeshNode.Position, node.MeshNode.Rotation);
                    mw.SetTransform(localToWorld);
                }
                mw.SetImageType(texExtension);
                if (node.MeshNode.GetType().Equals(typeof(MeshSceneNode)))
                {
                    mw.WriteMesh(device.FileSystem.CreateWriteFile(filename), ((MeshSceneNode)(node.MeshNode)).Mesh, MeshWriterFlag.None);
                }
                //else
                //    mw.WriteMesh(device.FileSystem.CreateWriteFile(filename), ((TerrainSceneNodeWolvenKit)(node.MeshNode)).Mesh, MeshWriterFlag.None);
                mw.Drop();
            }
        }
        void ProcessCommand()
        {
            queueSizeBar.Invoke((MethodInvoker) delegate
            {
                if (commandQueue.Count > queueSizeBar.Maximum)
                {
                    queueSizeBar.Maximum = commandQueue.Count;
                    queueSizeBar.Value   = queueSizeBar.Maximum;
                }
                else
                {
                    queueSizeBar.Value = commandQueue.Count;
                }
            });

            RenderMessage m;

            if (commandQueue.TryDequeue(out m))
            {
                switch (m.Message)
                {
                case MessageType.SHOW_NODE:
                {
                    m.Node.Visible = true;
                    var camera = smgr.ActiveCamera;

                    // just set the target
                    camera.Target      = m.Node.AbsolutePosition;
                    lightNode.Position = camera.Position;
                }
                break;

                case MessageType.HIDE_NODE:
                {
                    m.Node.Visible = false;
                }
                break;

                case MessageType.SELECT_NODE:
                {
                    // highlight and
                    smgr.SelectNode(m.Node);
                    var camera = smgr.ActiveCamera;

                    // just set the target
                    camera.Target      = m.Node.AbsolutePosition;
                    lightNode.Position = camera.Position;
                }
                break;

                case MessageType.ADD_MESH_NODE:
                {
                    IrrlichtLime.Scene.Mesh mesh = smgr.GetStaticMesh(depot + m.MeshName);
                    foreach (var mb in mesh.MeshBuffers)
                    {
                        totalVertexCount += mb.VertexCount;
                    }
                    MeshSceneNode meshNode = smgr.AddMeshSceneNode(mesh, worldNode, meshId++, m.Translation, m.Rotation);
#if DEBUG
                    meshNode.Name = m.MeshName;
#endif
                    meshNode.Grab();

                    RenderTreeNode rn = new RenderTreeNode(m.MeshName, meshNode);
                    if (m.TreeNode.GetNodeCount(false) > 0)
                    {
                        // TODO: does this need to be invoked?
                        sceneView.Invoke((MethodInvoker) delegate
                            {
                                m.TreeNode.Nodes.Add(rn);
                            });
                    }
                    else
                    {
                        sceneView.Invoke((MethodInvoker) delegate
                            {
                                sceneView.Nodes.Add(m.TreeNode);
                                m.TreeNode.Nodes.Add(rn);
                            });
                    }

                    ++totalMeshCount;

                    vertexCountText.Text = "Vertices: " + totalVertexCount.ToString();
                    meshCountText.Text   = "Meshes: " + totalMeshCount.ToString();
                }
                break;

                case MessageType.ADD_TERRAIN_NODE:
                {
                    var meshNode = smgr.AddTerrainSceneNodeWolvenKit(depot + m.MeshName, worldNode, meshId, m.TileRes, m.MaxHeight, m.MinHeight, m.TerrainSize, m.Translation);
                    meshNode.Grab();
                    foreach (var mb in meshNode.Mesh.MeshBuffers)
                    {
                        totalVertexCount += mb.VertexCount;
                    }

                    RenderTreeNode rn = new RenderTreeNode("Tile " + meshId.ToString(), meshNode);
                    meshId++;

                    if (m.TreeNode.GetNodeCount(false) > 0)
                    {
                        // TODO: does this need to be invoked?
                        sceneView.Invoke((MethodInvoker) delegate
                            {
                                m.TreeNode.Nodes.Add(rn);
                            });
                    }
                    else
                    {
                        sceneView.Invoke((MethodInvoker) delegate
                            {
                                sceneView.Nodes.Add(m.TreeNode);
                                m.TreeNode.Nodes.Add(rn);
                            });
                    }

                    ++totalMeshCount;

                    vertexCountText.Text = "Vertices: " + totalVertexCount.ToString();
                    meshCountText.Text   = "Meshes: " + totalMeshCount.ToString();
                }
                break;

                case MessageType.DESELECT_NODE:
                {
                    smgr.DeselectNode();
                }
                break;

                case MessageType.HIGHLIGHT_NODE:
                {
                    smgr.SelectNode(m.Node);
                }
                break;

                case MessageType.SHUTDOWN:
                {
                    device.Yield();
                }
                break;

                default:
                    break;
                }
            }
        }