Ejemplo n.º 1
0
        internal static bool FinalizeBuild()
        {
            if (brushesBuilt > 0)
            {
                buildContext.WriteVisualMappings();
            }

            // Ensure a mesh group exists
            bool newGroupCreated = Prepare(rootTransform);

            if (brushesBuilt > 0 || polygonsRemoved || newGroupCreated)
            {
                MeshGroupManager.Cleanup(meshGroupHolder);

                MeshGroupManager.BuildVisual(meshGroupHolder, buildContext.VisualPolygonIndex, buildSettings, buildContext, materialMeshDictionary);

                if (buildSettings.GenerateCollisionMeshes)
                {
                    MeshGroupManager.BuildCollision(meshGroupHolder, buildContext.CollisionPolygonIndex, buildSettings, collisionMeshDictionary);
                }

                // All done
                DateTime time2 = DateTime.Now;

                buildContext.buildMetrics.BuildMetaData = (time1 - buildStartTime).TotalSeconds + " " + (time2 - time1).TotalSeconds + " " + brushesBuilt;
                buildContext.buildMetrics.BuildTime     = (float)(DateTime.Now - buildStartTime).TotalSeconds;
                buildInProgress = false;
                return(true);
            }
            else
            {
                buildInProgress = false;
                return(false);
            }
        }
Ejemplo n.º 2
0
        internal static void CoreBuild(object state)
        {
            MeshGroupManager.OnFinalizeVisualMesh    = onFinalizeVisualMesh;
            MeshGroupManager.OnFinalizeCollisionMesh = onFinalizeCollisionMesh;

            if (forceRebuild)
            {
                buildContext.ClearAll();
            }

            buildStartTime = DateTime.Now;

            int brushesToBuild = 0;

            brushesBuilt = 0;

            BrushCache[] allBrushCaches = new BrushCache[brushes.Count];

            int totalPolygons = 0;

            for (int i = 0; i < allBrushCaches.Length; i++)
            {
                allBrushCaches[i] = brushes[i].BrushCache;
                totalPolygons    += allBrushCaches[i].Polygons.Length;
            }

            PolygonEntry[] oldVisualPolygonIndex    = buildContext.VisualPolygonIndex;
            PolygonEntry[] oldCollisionPolygonIndex = buildContext.CollisionPolygonIndex;

            PolygonEntry[] newVisualPolygonIndex    = new PolygonEntry[totalPolygons];
            PolygonEntry[] newCollisionPolygonIndex = new PolygonEntry[totalPolygons];

            int polygonUniqueID = 0;

            // Walk through each brush, assigning unique IDs to each polygon (since Unity serialisation will break
            // references on a recompile, reload etc)
            for (int i = 0; i < allBrushCaches.Length; i++)
            {
                brushes[i].AssignUniqueIDs(polygonUniqueID);

                // TODO: Find a way to remove this when Nova is removed
                polygonUniqueID += allBrushCaches[i].AssignUniqueIDs(polygonUniqueID,
                                                                     brushes[i].IsVisible,
                                                                     oldVisualPolygonIndex,
                                                                     newVisualPolygonIndex,
                                                                     brushes[i].HasCollision,
                                                                     oldCollisionPolygonIndex,
                                                                     newCollisionPolygonIndex);
            }

            buildContext.VisualPolygonIndex    = newVisualPolygonIndex;
            buildContext.CollisionPolygonIndex = newCollisionPolygonIndex;

            // Create a list of builders that need to be built
            bool[] shouldBuildVisible   = new bool[allBrushCaches.Length];
            bool[] shouldBuildCollision = new bool[allBrushCaches.Length];

            for (int brushIndex = 0; brushIndex < allBrushCaches.Length; brushIndex++)
            {
                if (!allBrushCaches[brushIndex].Built && brushes[brushIndex].IsVisible)
                {
                    shouldBuildVisible[brushIndex] = true;
                    brushesToBuild++;

                    // Mark all the intersecting brushes as needing to build
                    foreach (BrushCache brushCache in allBrushCaches[brushIndex].IntersectingVisualBrushCaches)
                    {
                        // TODO: This is slower than it needs to be
                        int otherIndex = Array.IndexOf(allBrushCaches, brushCache);
                        if (otherIndex != -1)
                        {
                            if (!shouldBuildVisible[otherIndex] && brushes[otherIndex].IsVisible)
                            {
                                shouldBuildVisible[otherIndex] = true;
                                brushesToBuild++;

                                if (brushes[otherIndex].Mode == CSGMode.Subtract)
                                {
                                    foreach (BrushCache brushCache2 in allBrushCaches[otherIndex].IntersectingVisualBrushCaches)
                                    {
                                        // TODO: This is slower than it needs to be
                                        int otherIndex2 = Array.IndexOf(allBrushCaches, brushCache2);
                                        if (otherIndex2 != -1)
                                        {
                                            if (!shouldBuildVisible[otherIndex2] && brushes[otherIndex2].IsVisible)
                                            {
                                                shouldBuildVisible[otherIndex2] = true;
                                                brushesToBuild++;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            for (int brushIndex = 0; brushIndex < allBrushCaches.Length; brushIndex++)
            {
                if (!allBrushCaches[brushIndex].Built && brushes[brushIndex].HasCollision)
                {
                    shouldBuildCollision[brushIndex] = true;
                    // TODO: This is slower than it needs to be
                    foreach (BrushCache brushCache in allBrushCaches[brushIndex].IntersectingCollisionBrushCaches)
                    {
                        int otherIndex = Array.IndexOf(allBrushCaches, brushCache);
                        if (otherIndex != -1)
                        {
                            if (!shouldBuildCollision[otherIndex] && brushes[otherIndex].HasCollision)
                            {
                                shouldBuildCollision[otherIndex] = true;
                                brushesToBuild++;

                                if (brushes[otherIndex].Mode == CSGMode.Subtract)
                                {
                                    foreach (BrushCache brushCache2 in allBrushCaches[otherIndex].IntersectingCollisionBrushCaches)
                                    {
                                        // TODO: This is slower than it needs to be
                                        int otherIndex2 = Array.IndexOf(allBrushCaches, brushCache2);
                                        if (otherIndex2 != -1)
                                        {
                                            if (!shouldBuildCollision[otherIndex2] && brushes[otherIndex2].HasCollision)
                                            {
                                                shouldBuildCollision[otherIndex2] = true;
                                                brushesToBuild++;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            for (int brushIndex = 0; brushIndex < allBrushCaches.Length; brushIndex++)
            {
                if (shouldBuildVisible[brushIndex] || shouldBuildCollision[brushIndex])
                {
                    allBrushCaches[brushIndex].ResetForBuild(newVisualPolygonIndex, newCollisionPolygonIndex);
                }
            }
            bool showProgressBar = false;

            if (DateTime.Now - buildStartTime > new TimeSpan(0, 0, 1))
            {
                showProgressBar = true;
                if (state == null && onProgressChange != null)                // Can only fire on main thread
                {
                    onProgressChange(0);
                }
            }

            // TODO: All this should be possible to parallelise.
            for (int brushIndex = 0; brushIndex < allBrushCaches.Length; brushIndex++)
            {
                if (shouldBuildVisible[brushIndex])
                {
                    // Intersecting builders can probably be calculated at edit time
                    BrushBuilder.Build(allBrushCaches[brushIndex], brushIndex, allBrushCaches, false);

                    brushesBuilt++;

                    // If we are not required to build collision (either for this brush, or at all) then we've built it!
                    if (!shouldBuildCollision[brushIndex] || !buildSettings.GenerateCollisionMeshes)
                    {
                        allBrushCaches[brushIndex].SetBuilt();
                    }

                    if (showProgressBar)
                    {
                        if (state == null && onProgressChange != null)                        // Can only fire on main thread
                        {
                            onProgressChange(brushesBuilt / (float)brushesToBuild);
                        }
                    }
                    else
                    {
                        if (DateTime.Now - buildStartTime > new TimeSpan(0, 0, 1))
                        {
                            showProgressBar = true;
                            if (state == null && onProgressChange != null)                            // Can only fire on main thread
                            {
                                onProgressChange(brushesBuilt / (float)brushesToBuild);
                            }
                        }
                    }
                }
            }

            for (int brushIndex = 0; brushIndex < allBrushCaches.Length; brushIndex++)
            {
                if (shouldBuildVisible[brushIndex])
                {
                    // Intersecting builders can probably be calculated at edit time
                    BrushCache.ReclaimStolenVisualPolygons(allBrushCaches[brushIndex]);
                }
            }

            if (buildSettings.GenerateCollisionMeshes)
            {
                for (int brushIndex = 0; brushIndex < allBrushCaches.Length; brushIndex++)
                {
                    if (shouldBuildCollision[brushIndex])
                    {
                        if (allBrushCaches[brushIndex].CollisionVisualEqual)
                        {
                        }
                        else
                        {
                            // Intersecting builders can probably be calculated at edit time
                            BrushBuilder.Build(allBrushCaches[brushIndex], brushIndex, allBrushCaches, true);

                            brushesBuilt++;

                            if (showProgressBar)
                            {
                                if (state == null && onProgressChange != null)                                // Can only fire on main thread
                                {
                                    onProgressChange(brushesBuilt / (float)brushesToBuild);
                                }
                            }
                            else
                            {
                                if (DateTime.Now - buildStartTime > new TimeSpan(0, 0, 1))
                                {
                                    showProgressBar = true;
                                    if (state == null && onProgressChange != null)                                    // Can only fire on main thread
                                    {
                                        onProgressChange(brushesBuilt / (float)brushesToBuild);
                                    }
                                }
                            }
                        }

                        allBrushCaches[brushIndex].SetBuilt();
                    }
                }

                for (int brushIndex = 0; brushIndex < allBrushCaches.Length; brushIndex++)
                {
                    if (shouldBuildCollision[brushIndex])
                    {
                        if (!allBrushCaches[brushIndex].CollisionVisualEqual)
                        {
                            // Intersecting builders can probably be calculated at edit time
                            BrushCache.ReclaimStolenCollisionPolygons(allBrushCaches[brushIndex]);
                        }
                    }
                }
            }

            time1 = DateTime.Now;

            // TODO: Can parallelise the vertex/index buffer generation, built putting them into mesh needs to be main thread
            // Triangulate the new polygons
            if (brushesBuilt > 0)
            {
                //VisualDebug.ClearAll();

                Dictionary <int, List <Polygon> > allGroupedPolygons = new Dictionary <int, List <Polygon> >();

                for (int brushIndex = 0; brushIndex < allBrushCaches.Length; brushIndex++)
                {
                    if (shouldBuildVisible[brushIndex])
                    {
                        // Grab the polygons grouped by ID, optimizing them if requested
                        Dictionary <int, List <Polygon> > groupedPolygons = null;
                        if (buildSettings.OptimizeGeometry)
                        {
                            // Return the optimal list of polygons (this call also updates BuiltVisualPolygons)
                            groupedPolygons = BrushCache.OptimizeVisual(allBrushCaches[brushIndex]);
                        }
                        else
                        {
                            groupedPolygons = allBrushCaches[brushIndex].GetGroupedBuiltVisualPolygons();
                        }

                        // Set the visual mapping from the built polygons (used by SurfaceEditor)
                        List <Polygon> polygons = allBrushCaches[brushIndex].BuiltVisualPolygons;
                        buildContext.SetVisualMapping(brushes[brushIndex], polygons);

                        // Add each set of polygons to the dictionary to be triangulated
                        foreach (KeyValuePair <int, List <Polygon> > row in groupedPolygons)
                        {
                            allGroupedPolygons.Add(row.Key, row.Value);
                        }
                    }
                }

                bool useIndividualVertices = buildSettings.GenerateLightmapUVs;                 // Generate individual vertices for unwrapped geometry

                MeshGroupManager.TriangulateNewPolygons(useIndividualVertices, allGroupedPolygons, buildContext.VisualPolygonIndex);

                if (buildSettings.GenerateCollisionMeshes)
                {
                    allGroupedPolygons.Clear();

                    for (int brushIndex = 0; brushIndex < allBrushCaches.Length; brushIndex++)
                    {
                        if (shouldBuildCollision[brushIndex])
                        {
                            if (allBrushCaches[brushIndex].CollisionVisualEqual)
                            {
                                // Intersection sets equal, so just copy visual triangulation
                                List <Polygon> builtVisualPolygons = allBrushCaches[brushIndex].BuiltVisualPolygons;
                                for (int i = 0; i < builtVisualPolygons.Count; i++)
                                {
                                    PolygonEntry visualPolygon = buildContext.VisualPolygonIndex[builtVisualPolygons[i].UniqueIndex];
                                    if (visualPolygon != null)
                                    {
                                        buildContext.CollisionPolygonIndex[builtVisualPolygons[i].UniqueIndex] = visualPolygon.DeepCopy();
                                    }
                                }
                            }
                            else
                            {
                                // Intersection sets are different, need to triangulate separately
                                Dictionary <int, List <Polygon> > groupedPolygons = null;
                                if (buildSettings.OptimizeGeometry)
                                {
                                    // Return the optimal list of polygons (this call also updates BuiltCollisionPolygons)
                                    groupedPolygons = BrushCache.OptimizeCollision(allBrushCaches[brushIndex]);
                                }
                                else
                                {
                                    groupedPolygons = allBrushCaches[brushIndex].GetGroupedBuiltCollisionPolygons();
                                }

                                // Add each set of polygons to the dictionary to be triangulated
                                foreach (KeyValuePair <int, List <Polygon> > row in groupedPolygons)
                                {
                                    allGroupedPolygons.Add(row.Key, row.Value);
                                }
                            }
                        }
                    }

                    useIndividualVertices = false;                     // Never use individual vertices for collision geometry
                    MeshGroupManager.TriangulateNewPolygons(useIndividualVertices, allGroupedPolygons, buildContext.CollisionPolygonIndex);
                }
            }

            // If multithreaded
            if (state != null)
            {
                // All done, tell the main thread to finish the build up
                readyForFinalize = true;
            }
        }