mirror of
				https://github.com/GayPizzaSpecifications/voxelotl-engine.git
				synced 2025-11-04 02:59:37 +00:00 
			
		
		
		
	implement parallel chunk mesh building
This commit is contained in:
		@ -54,6 +54,7 @@ add_executable(Voxelotl MACOSX_BUNDLE
 | 
			
		||||
  # Game logic classes
 | 
			
		||||
  Chunk.swift
 | 
			
		||||
  ChunkGeneration.swift
 | 
			
		||||
  ChunkMeshGeneration.swift
 | 
			
		||||
  WorldGenerator.swift
 | 
			
		||||
  CubeMeshBuilder.swift
 | 
			
		||||
  ChunkMeshBuilder.swift
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,5 @@
 | 
			
		||||
struct ChunkMeshBuilder {
 | 
			
		||||
  public static func build(world: World, chunkID: SIMD3<Int>) -> Mesh<VertexPositionNormalColorTexcoord, UInt16> {
 | 
			
		||||
    guard let chunk = world.getChunk(id: chunkID) else { return .empty }
 | 
			
		||||
 | 
			
		||||
  public static func build(world: World, chunk: Chunk) -> Mesh<VertexPositionNormalColorTexcoord, UInt16> {
 | 
			
		||||
    var vertices = [VertexPositionNormalColorTexcoord]()
 | 
			
		||||
    var indices = [UInt16]()
 | 
			
		||||
    chunk.forEach { block, position in
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										47
									
								
								Sources/Voxelotl/ChunkMeshGeneration.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								Sources/Voxelotl/ChunkMeshGeneration.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
			
		||||
import Foundation
 | 
			
		||||
 | 
			
		||||
public struct ChunkMeshGeneration {
 | 
			
		||||
  private let queue: OperationQueue
 | 
			
		||||
  private let localReadyMeshes = ConcurrentDictionary<SIMD3<Int>, RendererMesh>()
 | 
			
		||||
 | 
			
		||||
  weak var game: Game?
 | 
			
		||||
  weak var renderer: Renderer?
 | 
			
		||||
 | 
			
		||||
  init(queue: DispatchQueue) {
 | 
			
		||||
    self.queue = OperationQueue()
 | 
			
		||||
    self.queue.underlyingQueue = queue
 | 
			
		||||
    self.queue.maxConcurrentOperationCount = 8
 | 
			
		||||
    self.queue.qualityOfService = .userInitiated
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public mutating func generate(chunkID: SIMD3<Int>, chunk: Chunk) {
 | 
			
		||||
    self.queueGenerateJob(chunkID: chunkID, chunk: chunk)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  func queueGenerateJob(chunkID: SIMD3<Int>, chunk: Chunk) {
 | 
			
		||||
    self.queue.addOperation {
 | 
			
		||||
      guard let game = self.game else {
 | 
			
		||||
        return
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      guard let renderer = self.renderer else {
 | 
			
		||||
        return
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      let mesh = ChunkMeshBuilder.build(world: game.world, chunk: chunk)
 | 
			
		||||
      self.localReadyMeshes[chunkID] = renderer.createMesh(mesh)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public mutating func acceptReadyMeshes() {
 | 
			
		||||
    guard let game = self.game else {
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    queue.waitUntilAllOperationsAreFinished()
 | 
			
		||||
 | 
			
		||||
    for (chunkID, mesh) in self.localReadyMeshes.take() {
 | 
			
		||||
      game.renderChunks.updateValue(mesh, forKey: chunkID)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -27,6 +27,7 @@ class Game: GameDelegate {
 | 
			
		||||
  var world = World()
 | 
			
		||||
  var cubeMesh: RendererMesh?
 | 
			
		||||
  var renderChunks = [SIMD3<Int>: RendererMesh]()
 | 
			
		||||
  var chunkMeshGeneration: ChunkMeshGeneration!
 | 
			
		||||
 | 
			
		||||
  func create(_ renderer: Renderer) {
 | 
			
		||||
    self.resetPlayer()
 | 
			
		||||
@ -35,6 +36,9 @@ class Game: GameDelegate {
 | 
			
		||||
    self.cubeMesh = renderer.createMesh(CubeMeshBuilder.build(bound: .fromUnitCube(position: .zero, scale: .one)))
 | 
			
		||||
 | 
			
		||||
    renderer.clearColor = Color<Double>.black.mix(.white, 0.1).linear
 | 
			
		||||
    self.chunkMeshGeneration = .init(queue: .global(qos: .userInitiated))
 | 
			
		||||
    self.chunkMeshGeneration.game = self
 | 
			
		||||
    self.chunkMeshGeneration.renderer = renderer
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private func resetPlayer() {
 | 
			
		||||
@ -110,13 +114,9 @@ class Game: GameDelegate {
 | 
			
		||||
 | 
			
		||||
    // Update chunk meshes if needed
 | 
			
		||||
    self.world.handleRenderDamagedChunks { id, chunk in
 | 
			
		||||
      let mesh = ChunkMeshBuilder.build(world: self.world, chunkID: id)
 | 
			
		||||
      if let renderMesh = renderer.createMesh(mesh) {
 | 
			
		||||
        self.renderChunks[id] = renderMesh
 | 
			
		||||
      } else {
 | 
			
		||||
        self.renderChunks.removeValue(forKey: id)
 | 
			
		||||
      }
 | 
			
		||||
      self.chunkMeshGeneration.generate(chunkID: id, chunk: chunk)
 | 
			
		||||
    }
 | 
			
		||||
    self.chunkMeshGeneration.acceptReadyMeshes()
 | 
			
		||||
 | 
			
		||||
    for (id, chunk) in self.renderChunks {
 | 
			
		||||
      let drawPos = SIMD3<Float>(id &<< Chunk.shift)
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user