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 showAllButton_Click(object sender, EventArgs e)
        {
            progressBar.Maximum = sceneView.Nodes.Count;
            progressBar.Value   = 0;

            foreach (TreeNode node in sceneView.Nodes)
            {
                node.Checked = true;
                foreach (RenderTreeNode n in node.Nodes)
                {
                    n.Checked = true;
                    RenderMessage message = new RenderMessage(MessageType.SHOW_NODE, n.MeshNode);
                    commandQueue.Enqueue(message);

                    progressBar.PerformStep();
                }
            }

            progressBar.Value = 0;
        }
        private void sceneView_AfterCheck(object sender, TreeViewEventArgs e)
        {
            TreeNode node = e.Node;

            if (node.Checked)
            {
                if (node.Nodes.Count > 0)
                {
                    foreach (RenderTreeNode n in node.Nodes)
                    {
                        n.Checked = true;
                        RenderMessage m = new RenderMessage(MessageType.SHOW_NODE, n.MeshNode);
                        commandQueue.Enqueue(m);
                    }
                }
                else
                {
                    RenderMessage m = new RenderMessage(MessageType.SHOW_NODE, ((RenderTreeNode)node).MeshNode);
                    commandQueue.Enqueue(m);
                }
            }
            else
            {
                if (node.Nodes.Count > 0)
                {
                    foreach (RenderTreeNode n in node.Nodes)
                    {
                        n.Checked = false;
                        RenderMessage m = new RenderMessage(MessageType.HIDE_NODE, n.MeshNode);
                        commandQueue.Enqueue(m);
                    }
                }
                else
                {
                    RenderMessage m = new RenderMessage(MessageType.HIDE_NODE, ((RenderTreeNode)node).MeshNode);
                    commandQueue.Enqueue(m);
                }
            }
        }
        private void irrlichtPanel_MouseClick(object sender, MouseEventArgs e)
        {
            // need to have a click plus the ctrl key down
            if (pickKeyDown)
            {
                ViewFrustum f = smgr.ActiveCamera.ViewFrustum;

                Vector3Df farLeftUp   = f.FarLeftUp;
                Vector3Df lefttoright = f.FarRightUp - farLeftUp;
                Vector3Df uptodown    = f.FarLeftDown - farLeftUp;

                float dx = e.X / (float)viewPort.Width;
                float dy = e.Y / (float)viewPort.Height;

                Line3Df   ray        = new Line3Df(f.CameraPosition, farLeftUp + (lefttoright * dx) + (uptodown * dy));
                SceneNode pickedNode = smgr.SceneCollisionManager.GetSceneNodeFromRayBB(ray);

                if (pickedNode != null)
                {
                    RenderMessage message = new RenderMessage(MessageType.HIGHLIGHT_NODE, pickedNode);
                    commandQueue.Enqueue(message);

                    propertiesDlg.SetProperties(pickedNode);
                    if (!propertiesDlg.Visible)
                    {
                        propertiesDlg.Show(this);
                    }

                    if (backgroundSearcher.IsBusy)
                    {
                        backgroundSearcher.CancelAsync();
                    }
                    backgroundSearcher.RunWorkerAsync(pickedNode.ID);
                }
            }
        }
        private void AddLayer(string layerFileName, string layerName, ref int meshId)
        {
            float RADIANS_TO_DEGREES = (float)(180 / Math.PI);

            CR2WFile layer;

            using (var fs = new FileStream(layerFileName, FileMode.Open, FileAccess.Read))
                using (var reader = new BinaryReader(fs))
                {
                    layer = new CR2WFile();
                    layer.Read(reader);
                    fs.Close();
                }

            TreeNode layerNode = new TreeNode(layerName);

            foreach (var chunk in layer.chunks)
            {
                if (chunk.REDType == "CSectorData")
                {
                    CSectorData sd = (CSectorData)chunk.data;

                    progressBar.Invoke((MethodInvoker) delegate
                    {
                        progressBar.Maximum = sd.BlockData.Count;
                    });

                    // only add sector node if there are meshes
                    foreach (var block in sd.BlockData)
                    {
                        if (block.packedObjectType == Enums.BlockDataObjectType.Mesh)
                        {
                            SVector3D  position = block.position;
                            CMatrix3x3 rot = block.rotationMatrix;
                            float      rx, ry, rz;
                            MatrixToEuler(rot, out rx, out ry, out rz); // radians

                            Vector3Df rotation    = new Vector3Df(rx * RADIANS_TO_DEGREES, ry * RADIANS_TO_DEGREES, rz * RADIANS_TO_DEGREES);
                            Vector3Df translation = new Vector3Df(position.X.val, position.Y.val, position.Z.val);

                            SBlockDataMeshObject mo = (SBlockDataMeshObject)block.packedObject;
                            ushort meshIndex        = mo.meshIndex.val;
                            if (meshIndex > sd.Resources.Count)
                            {
                                continue;
                            }
                            string meshName = sd.Resources[meshIndex].pathHash.val;

                            if (string.IsNullOrEmpty(meshName))
                            {
                                continue;
                            }

                            RenderMessage message = new RenderMessage(MessageType.ADD_MESH_NODE, meshName, translation, rotation, layerNode);
                            commandQueue.Enqueue(message);

                            progressBar.Invoke((MethodInvoker) delegate
                            {
                                progressBar.PerformStep();
                            });
                        }
                    }
                }
            }
        }
        private void AddTerrain(CClipMap info, ref int meshId)
        {
            TreeNode terrainNode = new TreeNode("Terrain");

            float maxHeight       = info.HighestElevation.val;
            float minHeight       = info.LowestElevation.val;
            uint  numTilesPerEdge = info.NumTilesPerEdge.val;
            float terrainSize     = info.TerrainSize.val / numTilesPerEdge;

            uint tileRes = 0;
            int  tileLOD = 0;

            Vector3Df startPoint = new Vector3Df(info.TerrainCorner.X.val, info.TerrainCorner.Y.val, info.TerrainCorner.Z.val);

            //string texFileName = info.Material.DepotPath; // this is a .w2mg
            //Texture terrainTex = driver.GetTexture("");
            Vector3Df nextRow = new Vector3Df(startPoint);
            Vector3Df dy      = new Vector3Df(0.0f, terrainSize, 0.0f);
            Vector3Df dx      = new Vector3Df(terrainSize, 0.0f, 0.0f);

            progressBar.Invoke((MethodInvoker) delegate
            {
                progressBar.Maximum = (int)(numTilesPerEdge * numTilesPerEdge);
            });

            int index = 0;

            for (uint y = 0; y < numTilesPerEdge; ++y)
            {
                Vector3Df nextColumn = new Vector3Df(startPoint + dy * y);

                for (uint x = 0; x < numTilesPerEdge; ++x)
                {
                    var tile = info.TerrainTiles[index++];

                    Vector3Df nextPt = new Vector3Df(nextColumn + dx * x);


                    // read the .wter file to get the LOD we need
                    {
                        var wterFileName = depot + tile.DepotPath;

                        CR2WFile wter;
                        using (var fs = new FileStream(wterFileName, FileMode.Open, FileAccess.Read))
                            using (var reader = new BinaryReader(fs))
                            {
                                wter = new CR2WFile();
                                wter.Read(reader);
                                fs.Close();
                            }

                        CTerrainTile crw = (CTerrainTile)wter.chunks[0].data;
                        tileLOD = (int)crw.Groups[1].Lod1.val;
                        tileRes = (uint)crw.Groups[1].Resolution.val;
                    }

                    var tileFileName = tile.DepotPath;
                    tileFileName += ".";
                    tileFileName += tileLOD.ToString();
                    tileFileName += ".buffer";

                    RenderMessage message = new RenderMessage(MessageType.ADD_TERRAIN_NODE, tileFileName, tileRes, maxHeight, minHeight, terrainSize, nextPt, terrainNode);
                    commandQueue.Enqueue(message);

                    progressBar.Invoke((MethodInvoker) delegate
                    {
                        progressBar.PerformStep();
                    });
                }
            }
        }