void InitCSGTree() { csgTree = CSGUtility.LoadTree("import.xml", out instanceNodes); if (csgTree == null) { MessageBox.Show("Failed to load file"); return; } instanceNodeTranslations = new List <Vector3>(); if (instanceNodes != null && instanceNodes.Count > 0) { foreach (var node in instanceNodes) { instanceNodeTranslations.Add(node.LocalTranslation); } subInstanceBrushes = new HashSet <CSGNode>(); foreach (var node in instanceNodes) { foreach (var brush in CSGUtility.FindChildBrushes(node)) { subInstanceBrushes.Add(brush); } } allBrushes = (from node in CSGUtility.FindChildBrushes(csgTree) where !subInstanceBrushes.Contains(node) select node).ToList(); } else { allBrushes = CSGUtility.FindChildBrushes(csgTree).ToList(); } var updateNodes = new List <CSGNode>(); updateNodes.AddRange(allBrushes); updateNodes.AddRange(instanceNodes); UpdateMeshes(csgTree, updateNodes); }
public static ConcurrentDictionary <CSGNode, CSGMesh> ProcessCSGNodes(CSGNode root, IEnumerable <CSGNode> nodes) { var meshes = new ConcurrentDictionary <CSGNode, CSGMesh>(); var buildMesh = (Action <CSGNode>) delegate(CSGNode node) { CSGMesh mesh; if (!cachedBaseMeshes.TryGetValue(node, out mesh)) { // If the node we're performing csg on is a brush, we simply create the geometry from the planes // If the node is a more complicated node, we perform csg on it's child nodes and combine the // meshes that are created. // Note that right now we cache brushes per node, but we can improve on this by caching on // node type instead. Since lots of nodes will have the same geometry in real life and only // need to be created once. It won't help much in runtime performance considering they're // cached anyway, but it'll save on memory usage. if (node.NodeType != CSGNodeType.Brush) { var childNodes = CSGUtility.FindChildBrushes(node); var brushMeshes = ProcessCSGNodes(node, childNodes); mesh = CSGMesh.Combine(node.Translation, brushMeshes); } else { mesh = CSGMesh.CreateFromPlanes(node.Planes); } // Cache the mesh cachedBaseMeshes[node] = mesh; } // Clone the cached mesh so we can perform CSG on it. var clonedMesh = mesh.Clone(); node.Bounds.Set(clonedMesh.Bounds); meshes[node] = clonedMesh; }; var updateDelegate = (Action <KeyValuePair <CSGNode, CSGMesh> >) delegate(KeyValuePair <CSGNode, CSGMesh> item) { var processedNode = item.Key; var processedMesh = item.Value; var inputPolygons = processedMesh.Polygons; var insidePolygons = new List <Polygon>(inputPolygons.Count); var outsidePolygons = new List <Polygon>(inputPolygons.Count); var alignedPolygons = new List <Polygon>(inputPolygons.Count); var reversedPolygons = new List <Polygon>(inputPolygons.Count); CSGCategorization.Categorize(processedNode, processedMesh, root, inputPolygons, // these are the polygons that are categorized insidePolygons, alignedPolygons, reversedPolygons, outsidePolygons ); // Flag all non aligned polygons as being invisible, and store their categorizations // so we can use it if we instance this mesh. foreach (var polygon in insidePolygons) { polygon.Category = PolygonCategory.Inside; polygon.Visible = false; } foreach (var polygon in outsidePolygons) { polygon.Category = PolygonCategory.Outside; polygon.Visible = false; } foreach (var polygon in alignedPolygons) { polygon.Category = PolygonCategory.Aligned; } foreach (var polygon in reversedPolygons) { polygon.Category = PolygonCategory.ReverseAligned; } }; // // Here we run build the meshes and perform csg on them either in serial or parallel // /* * foreach (var node in nodes) * buildMesh(node); * CSGUtility.UpdateBounds(root); * foreach (var item in meshes) * updateDelegate(item); * /*/ Parallel.ForEach(nodes, buildMesh); CSGUtility.UpdateBounds(root); Parallel.ForEach(meshes, updateDelegate); //*/ return(meshes); }