void AllocateWork(Chunk chunk, TerrainWorkerAction action) { if (GlobalNetwork.IsServer && action != TerrainWorkerAction.Populate) { return; } chunk.BeingWorkedOn = true; // Find the first worker that isnt busy, or the worker with the smallest // work count and add the action to it's queue. TerrainWorker worker = null; if (action != TerrainWorkerAction.CalculateLighting) { for (int i = 0; i < workers.Length; i++) { TerrainWorker _worker = workers[i]; if (!_worker.IsBusy && (worker == null || _worker.WorkCount < worker.WorkCount)) { worker = _worker; } else if (i == workers.Length - 1 && worker == null) { worker = _worker; } } } else { worker = workers[workers.Length - 1]; } worker.Enqueue(chunk, action); }
public void Enqueue(Chunk chunk, TerrainWorkerAction action) { if (disposed) { throw new ObjectDisposedException("TerrainWorker", "Cannot enqueue work, this TerrainWorker has been disposed!"); } queue.Enqueue(new TerrainWorkerInstruction(chunk, action)); resetEvent.Set(); }
public void Generate(int width, int height, int depth) { Chunk.rand = Maths.RandomRange(-1, 1); Width = width; Height = height; Depth = depth; currentPreAction = TerrainWorkerAction.Populate; preGenerating = true; PopulateChunks(); }
public override void Update(float deltaTime) { if (!Ready && preGenerating) { // Handle pre-generation if (IsWorkersDone()) { if (currentPreAction == TerrainWorkerAction.Populate) { currentPreAction = TerrainWorkerAction.Shape; ShapeChunks(); } else if (currentPreAction == TerrainWorkerAction.Shape && !GlobalNetwork.IsServer) { currentPreAction = TerrainWorkerAction.CalculateLighting; CalculateChunkLighting(); } else if (currentPreAction == TerrainWorkerAction.CalculateLighting && !GlobalNetwork.IsServer) { currentPreAction = TerrainWorkerAction.BuildMesh; BuildChunkMeshes(); } else if (currentPreAction == TerrainWorkerAction.BuildMesh && !GlobalNetwork.IsServer) { while (MeshReadyChunks.Count > 0) { Chunk chunk; if (MeshReadyChunks.TryDequeue(out chunk)) { chunk.CreateOrUpdateMesh(BufferUsageHint.DynamicDraw); chunk.State = ChunkState.Renderable; chunk.BeingWorkedOn = false; } } Ready = true; } else if (currentPreAction != TerrainWorkerAction.Populate && GlobalNetwork.IsServer) { Ready = true; } } } else if (!GlobalNetwork.IsServer) { // Every so often, check if any chunks need an update. if (applyWorkTime > 0) { applyWorkTime -= deltaTime; } else { applyWorkTime = applyWorkDelay; foreach (Chunk chunk in Chunks.Values) { if (!chunk.BeingWorkedOn && (chunk.IsDirty || chunk.Lighting.IsDirty)) { if (chunk.State == ChunkState.Renderable || chunk.Lighting.IsDirty) { chunk.State = ChunkState.Unlit; } if (chunk.State == ChunkState.Unlit) { chunk.IsDirty = true; //if (chunk.Lighting.CanProcess()) AllocateWork(chunk, TerrainWorkerAction.CalculateLighting); } else if (chunk.State == ChunkState.Unbuilt) { if (chunk.Lighting.IsMeshReady()) { AllocateWork(chunk, TerrainWorkerAction.BuildMesh); } } } } } // Finish mesh ready chunks while (MeshReadyChunks.Count > 0) { Chunk chunk; if (MeshReadyChunks.TryDequeue(out chunk)) { chunk.CreateOrUpdateMesh(BufferUsageHint.DynamicDraw); chunk.State = ChunkState.Renderable; chunk.BeingWorkedOn = false; chunk.IsDirty = false; } } } }
public TerrainWorkerInstruction(Chunk chunk, TerrainWorkerAction action) { Chunk = chunk; Action = action; }