//Sending newly created Mesh to the GC, making the change visible, this is NOT threadsafe, the chunk must be done one by one. //This could lead to "lag" if too many chunks are sending their new mesh to the GC at the same time (during the same frame) //Maybe it will be worth to check is a limit of chunk by update must be placed (But this will slow down chunk creation time) private void SendMeshesToGC(int maximumUpdateOrderPossible) { int nbrchunksSend2GC = 0; //Process each chunk that are in IsOutsideLightSourcePropagated state, and not currently processed foreach (VisualChunk chunk in SortedChunks.Where(x => x.State == ChunkState.MeshesChanged && x.ThreadStatus == ThreadsManager.ThreadStatus.Idle && x.UpdateOrder == maximumUpdateOrderPossible)) { chunk.UpdateOrder = 0; chunk.Graphics.SendCubeMeshesToBuffers(); nbrchunksSend2GC++; #if PERFTEST if (chunk.ChunkID == Utopia.Worlds.Chunks.WorldChunks.perf.cubeChunkID) { Utopia.Worlds.Chunks.WorldChunks.perf.AddData("FINISHED"); Utopia.Worlds.Chunks.WorldChunks.perf.Actif = false; foreach (var data in Utopia.Worlds.Chunks.WorldChunks.perf.CollectedData) { Console.WriteLine(data); } } else { Utopia.Worlds.Chunks.WorldChunks.perf.AddData("SendMeshesToGC Started " + chunk.ChunkID); } #endif if (nbrchunksSend2GC > VisualWorldParameters.VisibleChunkInWorld.X) { break; } } }
//Landscape chunk Slicing visualization Handling private void SlicingUpdate(GameTime timeSpend) { if (SortedChunks.Count(x => x.State != ChunkState.DisplayInSyncWithMeshes) > 0) { return; } if (_inputsManager.ActionsManager.isTriggered(UtopiaActions.LandscapeSlicerUp)) { if (_sliceValue == -1) { _sliceValue = (int)_camManager.ActiveCamera.WorldPosition.ValueInterp.Y; } _sliceValue++; } if (_inputsManager.ActionsManager.isTriggered(UtopiaActions.LandscapeSlicerDown)) { if (_sliceValue == -1) { _sliceValue = (int)_camManager.ActiveCamera.WorldPosition.ValueInterp.Y; } _sliceValue--; } if (_inputsManager.ActionsManager.isTriggered(UtopiaActions.LandscapeSlicerOff)) { _sliceValue = -1; } }
private void ChunkUpdateManager() { int maximumUpdateOrderPossible = SortedChunks.Max(x => x.UpdateOrder); UpdateLeveled(); ChunkResyncing(); CreateNewChunk(); PropagateOuterChunkLights(); CreateChunkMeshes(maximumUpdateOrderPossible); SendMeshesToGC(maximumUpdateOrderPossible); }
//Will create new chunks based on chunks with state = Empty private void CreateNewChunk() { //Process each chunk that are in Empty state, and not currently processed foreach (VisualChunk chunk in SortedChunks.Where(x => (x.State == ChunkState.Empty || x.State == ChunkState.LandscapeCreated) && x.ThreadStatus == ThreadsManager.ThreadStatus.Idle)) { VisualChunk localChunk = chunk; //Start chunk creation process in a threaded way ! localChunk.ThreadStatus = ThreadsManager.ThreadStatus.Locked; //Lock the thread before entering async process. #if DEBUG localChunk.ThreadLockedBy = "CreateNewChunk"; #endif //SmartThread.ThreadPool.QueueWorkItem(ChunkCreationThreadedSteps_Threaded, chunk, WorkItemPriority.Normal); S33M3DXEngine.Threading.ThreadsManager.RunAsync(() => ChunkCreationThreadedSteps_Threaded(localChunk)); } }
private void CheckWrapping() { if (SortedChunks.Count(x => x.State != ChunkState.DisplayInSyncWithMeshes) > 0) { return; } // Get World Border line ! => Highest and lowest X et Z chunk components //Compute Player position against WorldRange var resultmin = new Vector3D(PlayerManager.Player.Position.X - VisualWorldParameters.WorldRange.Position.X, PlayerManager.Player.Position.Y - VisualWorldParameters.WorldRange.Position.Y, PlayerManager.Player.Position.Z - VisualWorldParameters.WorldRange.Position.Z); var resultmax = new Vector3D(VisualWorldParameters.WorldRange.Max.X - PlayerManager.Player.Position.X, VisualWorldParameters.WorldRange.Max.Y - PlayerManager.Player.Position.Y, VisualWorldParameters.WorldRange.Max.Z - PlayerManager.Player.Position.Z); float wrapOrder = float.MaxValue; ChunkWrapType operation = ChunkWrapType.Z_Plus1; //FindLowest value ! if (_chunkCreationTrigger > resultmin.X || _chunkCreationTrigger > resultmin.Z || _chunkCreationTrigger > resultmax.X || _chunkCreationTrigger > resultmax.Z) { if (resultmin.X < wrapOrder) { wrapOrder = (float)resultmin.X; operation = ChunkWrapType.X_Minus1; } if (resultmin.Z < wrapOrder) { wrapOrder = (float)resultmin.Z; operation = ChunkWrapType.Z_Minus1; } if (resultmax.X < wrapOrder) { wrapOrder = (float)resultmax.X; operation = ChunkWrapType.X_Plus1; } if (resultmax.Z < wrapOrder) { wrapOrder = (float)resultmax.Z; operation = ChunkWrapType.Z_Plus1; } _chunkWrapper.AddWrapOperation(operation); } }
//Will take the newly created chunks || the chunk that didn't had the outside light propagate (Border chunk), and propagate the light from the surroundings chunks private void PropagateOuterChunkLights() { //Process each chunk that are in InnerLightsSourcePropagated state, and not being currently processed foreach (VisualChunk chunk in SortedChunks.Where(x => (x.State == ChunkState.InnerLightsSourcePropagated || (x.IsOutsideLightSourcePropagated == false && x.IsBorderChunk == false && x.State >= ChunkState.InnerLightsSourcePropagated)) && x.ThreadStatus == ThreadsManager.ThreadStatus.Idle)) { VisualChunk localChunk = chunk; //all the surrounding chunks must have had their LightSources Processed at minimum. if (localChunk.IsBorderChunk == true || localChunk.SurroundingChunksMinimumState(ChunkState.InnerLightsSourcePropagated)) { //Check if the surrounding chunk from this chunk are in the correct state = ChunkState.InnerLightsSourcePropagated localChunk.ThreadStatus = ThreadsManager.ThreadStatus.Locked; //Lock the thread before entering async process. #if DEBUG localChunk.ThreadLockedBy = "PropagateOuterChunkLights"; #endif S33M3DXEngine.Threading.ThreadsManager.RunAsync(() => ChunkOuterLightPropagation_Threaded(localChunk)); } } }
private void CreateChunkMeshes(int maximumUpdateOrderPossible) { //Process each chunk that are in IsOutsideLightSourcePropagated state, and not currently processed foreach (VisualChunk chunk in SortedChunks.Where(x => x.State == ChunkState.OuterLightSourcesProcessed && x.ThreadStatus == ThreadsManager.ThreadStatus.Idle)) { VisualChunk localChunk = chunk; if (maximumUpdateOrderPossible > 0 && localChunk.UpdateOrder == 0) { continue; } //all the surrounding chunks must have had their LightSources Processed at minimum. if (localChunk.SurroundingChunksMinimumState(ChunkState.OuterLightSourcesProcessed)) { localChunk.ThreadStatus = ThreadsManager.ThreadStatus.Locked; #if DEBUG localChunk.ThreadLockedBy = "CreateChunkMeshes"; #endif S33M3DXEngine.Threading.ThreadsManager.RunAsync(() => CreateChunkMeshes_Threaded(localChunk), localChunk.UpdateOrder > 0 ? ThreadsManager.ThreadTaskPriority.High : ThreadsManager.ThreadTaskPriority.Normal); } } }
/// <summary> /// Enumerates all visible chunks by player (i.e. not frustum culled) /// </summary> /// <returns></returns> public IEnumerable <VisualChunk> VisibleChunks() { return(SortedChunks.Where(chunk => !chunk.Graphics.IsFrustumCulled)); }