mirror of
				https://github.com/GayPizzaSpecifications/voxelotl-engine.git
				synced 2025-11-04 10:59:39 +00:00 
			
		
		
		
	prep for chunk meshing
This commit is contained in:
		@ -36,6 +36,7 @@ add_executable(Voxelotl MACOSX_BUNDLE
 | 
			
		||||
  # Renderer classes
 | 
			
		||||
  Renderer/Material.swift
 | 
			
		||||
  Renderer/Environment.swift
 | 
			
		||||
  Renderer/Mesh.swift
 | 
			
		||||
  Renderer/Renderer.swift
 | 
			
		||||
 | 
			
		||||
  # Input wrappers
 | 
			
		||||
@ -44,6 +45,7 @@ add_executable(Voxelotl MACOSX_BUNDLE
 | 
			
		||||
  Input/Mouse.swift
 | 
			
		||||
 | 
			
		||||
  # Core utility classes
 | 
			
		||||
  CubeMeshBuilder.swift
 | 
			
		||||
  Color.swift
 | 
			
		||||
  Camera.swift
 | 
			
		||||
  FPSCalculator.swift
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
public struct Chunk {
 | 
			
		||||
public struct Chunk: Hashable {
 | 
			
		||||
  public static let shift = 4  // 16
 | 
			
		||||
  public static let size: Int = 1 << shift
 | 
			
		||||
  public static let mask: Int = size - 1
 | 
			
		||||
@ -63,6 +63,15 @@ public struct Chunk {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public func forEach(_ body: @escaping (Block, SIMD3<Int>) throws -> Void) rethrows {
 | 
			
		||||
    for i in 0..<Self.blockCount {
 | 
			
		||||
      try body(blocks[i], self.origin &+ SIMD3(
 | 
			
		||||
        x: i & Self.mask,
 | 
			
		||||
        y: (i &>> Self.shift) & Self.mask,
 | 
			
		||||
        z: (i &>> (Self.shift + Self.shift)) & Self.mask))
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public func map<T>(block transform: (Block, SIMD3<Int>) throws -> T) rethrows -> [T] {
 | 
			
		||||
    assert(self.blocks.count == Self.blockCount)
 | 
			
		||||
 | 
			
		||||
@ -112,12 +121,12 @@ public struct Chunk {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public enum BlockType: Equatable {
 | 
			
		||||
public enum BlockType: Hashable {
 | 
			
		||||
  case air
 | 
			
		||||
  case solid(_ color: Color<Float16>)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public struct Block {
 | 
			
		||||
public struct Block: Hashable {
 | 
			
		||||
  public var type: BlockType
 | 
			
		||||
 | 
			
		||||
  public init(_ type: BlockType) {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import Foundation
 | 
			
		||||
 | 
			
		||||
public struct Color<T: SIMDScalar>: Equatable {
 | 
			
		||||
public struct Color<T: SIMDScalar>: Hashable {
 | 
			
		||||
  private var _values: SIMD4<T>
 | 
			
		||||
 | 
			
		||||
  internal var values: SIMD4<T> { self._values }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										40
									
								
								Sources/Voxelotl/CubeMeshBuilder.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								Sources/Voxelotl/CubeMeshBuilder.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
			
		||||
public struct CubeMeshBuilder {
 | 
			
		||||
  public static func build(bound: AABB) -> Mesh<VertexPositionNormalTexcoord, UInt16> {
 | 
			
		||||
    let cubeVertices: [VertexPositionNormalTexcoord] = [
 | 
			
		||||
      .init(position: .init( bound.left, bound.bottom, bound.near), normal: .back,    texCoord: .init(0, 0)),
 | 
			
		||||
      .init(position: .init(bound.right, bound.bottom, bound.near), normal: .back,    texCoord: .init(1, 0)),
 | 
			
		||||
      .init(position: .init( bound.left,    bound.top, bound.near), normal: .back,    texCoord: .init(0, 1)),
 | 
			
		||||
      .init(position: .init(bound.right,    bound.top, bound.near), normal: .back,    texCoord: .init(1, 1)),
 | 
			
		||||
      .init(position: .init(bound.right, bound.bottom, bound.near), normal: .right,   texCoord: .init(0, 0)),
 | 
			
		||||
      .init(position: .init(bound.right, bound.bottom,  bound.far), normal: .right,   texCoord: .init(1, 0)),
 | 
			
		||||
      .init(position: .init(bound.right,    bound.top, bound.near), normal: .right,   texCoord: .init(0, 1)),
 | 
			
		||||
      .init(position: .init(bound.right,    bound.top,  bound.far), normal: .right,   texCoord: .init(1, 1)),
 | 
			
		||||
      .init(position: .init(bound.right, bound.bottom,  bound.far), normal: .forward, texCoord: .init(0, 0)),
 | 
			
		||||
      .init(position: .init( bound.left, bound.bottom,  bound.far), normal: .forward, texCoord: .init(1, 0)),
 | 
			
		||||
      .init(position: .init(bound.right,    bound.top,  bound.far), normal: .forward, texCoord: .init(0, 1)),
 | 
			
		||||
      .init(position: .init( bound.left,    bound.top,  bound.far), normal: .forward, texCoord: .init(1, 1)),
 | 
			
		||||
      .init(position: .init( bound.left, bound.bottom,  bound.far), normal: .left,    texCoord: .init(0, 0)),
 | 
			
		||||
      .init(position: .init( bound.left, bound.bottom, bound.near), normal: .left,    texCoord: .init(1, 0)),
 | 
			
		||||
      .init(position: .init( bound.left,    bound.top,  bound.far), normal: .left,    texCoord: .init(0, 1)),
 | 
			
		||||
      .init(position: .init( bound.left,    bound.top, bound.near), normal: .left,    texCoord: .init(1, 1)),
 | 
			
		||||
      .init(position: .init( bound.left, bound.bottom,  bound.far), normal: .down,    texCoord: .init(0, 0)),
 | 
			
		||||
      .init(position: .init(bound.right, bound.bottom,  bound.far), normal: .down,    texCoord: .init(1, 0)),
 | 
			
		||||
      .init(position: .init( bound.left, bound.bottom, bound.near), normal: .down,    texCoord: .init(0, 1)),
 | 
			
		||||
      .init(position: .init(bound.right, bound.bottom, bound.near), normal: .down,    texCoord: .init(1, 1)),
 | 
			
		||||
      .init(position: .init( bound.left,    bound.top, bound.near), normal: .up,      texCoord: .init(0, 0)),
 | 
			
		||||
      .init(position: .init(bound.right,    bound.top, bound.near), normal: .up,      texCoord: .init(1, 0)),
 | 
			
		||||
      .init(position: .init( bound.left,    bound.top,  bound.far), normal: .up,      texCoord: .init(0, 1)),
 | 
			
		||||
      .init(position: .init(bound.right,    bound.top,  bound.far), normal: .up,      texCoord: .init(1, 1))
 | 
			
		||||
    ]
 | 
			
		||||
    return .init(vertices: cubeVertices, indices: cubeIndices)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fileprivate let cubeIndices: [UInt16] = [
 | 
			
		||||
   0,  1,  2,  2,  1,  3,
 | 
			
		||||
   4,  5,  6,  6,  5,  7,
 | 
			
		||||
   8,  9, 10, 10,  9, 11,
 | 
			
		||||
  12, 13, 14, 14, 13, 15,
 | 
			
		||||
  16, 17, 18, 18, 17, 19,
 | 
			
		||||
  20, 21, 22, 22, 21, 23
 | 
			
		||||
]
 | 
			
		||||
@ -25,11 +25,15 @@ class Game: GameDelegate {
 | 
			
		||||
  var player = Player()
 | 
			
		||||
  var projection: matrix_float4x4 = .identity
 | 
			
		||||
  var world = World()
 | 
			
		||||
  var cubeMesh: RendererMesh?
 | 
			
		||||
  var renderChunks = [SIMD3<Int>: Mesh<VertexPositionNormalTexcoord, UInt16>]()
 | 
			
		||||
 | 
			
		||||
  func create(_ renderer: Renderer) {
 | 
			
		||||
    self.resetPlayer()
 | 
			
		||||
    self.generateWorld()
 | 
			
		||||
 | 
			
		||||
    self.cubeMesh = renderer.createMesh(CubeMeshBuilder.build(bound: .fromUnitCube(position: .zero, scale: .one)))
 | 
			
		||||
 | 
			
		||||
    renderer.clearColor = Color<Double>.black.mix(.white, 0.1).linear
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -104,8 +108,8 @@ class Game: GameDelegate {
 | 
			
		||||
            .init(angle: totalTime * 0.7, axis: .init(0, 0, 1)),
 | 
			
		||||
          color:    .init(r: 0.5, g: 0.5, b: 1).linear))
 | 
			
		||||
    }
 | 
			
		||||
    if !instances.isEmpty {
 | 
			
		||||
      renderer.batch(instances: instances, material: material, environment: env, camera: self.camera)
 | 
			
		||||
    if self.cubeMesh != nil && !instances.isEmpty {
 | 
			
		||||
      renderer.batch(instances: instances, mesh: self.cubeMesh!, material: material, environment: env, camera: self.camera)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,45 +1,45 @@
 | 
			
		||||
import simd
 | 
			
		||||
 | 
			
		||||
struct AABB {
 | 
			
		||||
public struct AABB {
 | 
			
		||||
  private var _bounds: simd_float2x3
 | 
			
		||||
 | 
			
		||||
  var lower: SIMD3<Float> {
 | 
			
		||||
  public var lower: SIMD3<Float> {
 | 
			
		||||
    get { _bounds[0] }
 | 
			
		||||
    set(row) { self._bounds[0] = row }
 | 
			
		||||
  }
 | 
			
		||||
  var upper: SIMD3<Float> {
 | 
			
		||||
  public var upper: SIMD3<Float> {
 | 
			
		||||
    get { _bounds[1] }
 | 
			
		||||
    set(row) { self._bounds[1] = row }
 | 
			
		||||
  }
 | 
			
		||||
  var center: SIMD3<Float> {
 | 
			
		||||
  public var center: SIMD3<Float> {
 | 
			
		||||
    get { (self._bounds[0] + self._bounds[1]) / 2 }
 | 
			
		||||
  }
 | 
			
		||||
  var size: SIMD3<Float> {
 | 
			
		||||
  public var size: SIMD3<Float> {
 | 
			
		||||
    get { self._bounds[1] - self._bounds[0] }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  var left: Float   { self._bounds[0].x }
 | 
			
		||||
  var bottom: Float { self._bounds[0].y }
 | 
			
		||||
  var far: Float    { self._bounds[0].z }
 | 
			
		||||
  var right: Float  { self._bounds[1].x }
 | 
			
		||||
  var top: Float    { self._bounds[1].y }
 | 
			
		||||
  var near: Float   { self._bounds[1].z }
 | 
			
		||||
  public var left: Float   { self._bounds[0].x }
 | 
			
		||||
  public var bottom: Float { self._bounds[0].y }
 | 
			
		||||
  public var far: Float    { self._bounds[0].z }
 | 
			
		||||
  public var right: Float  { self._bounds[1].x }
 | 
			
		||||
  public var top: Float    { self._bounds[1].y }
 | 
			
		||||
  public var near: Float   { self._bounds[1].z }
 | 
			
		||||
 | 
			
		||||
  private init(bounds: simd_float2x3) {
 | 
			
		||||
    self._bounds = bounds
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  init(from: SIMD3<Float>, to: SIMD3<Float>) {
 | 
			
		||||
  public init(from: SIMD3<Float>, to: SIMD3<Float>) {
 | 
			
		||||
    self.init(bounds: .init(from, to))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static func fromUnitCube(position: SIMD3<Float> = .zero, scale: SIMD3<Float> = .one) -> Self {
 | 
			
		||||
  public static func fromUnitCube(position: SIMD3<Float> = .zero, scale: SIMD3<Float> = .one) -> Self {
 | 
			
		||||
    self.init(
 | 
			
		||||
      from: position - scale,
 | 
			
		||||
      to:   position + scale)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  func touching(_ other: Self) -> Bool{
 | 
			
		||||
  public func touching(_ other: Self) -> Bool{
 | 
			
		||||
    let distLower = other._bounds[0] - self._bounds[1]  // x: left, y: bottom, z: far
 | 
			
		||||
    let distUpper = self._bounds[0] - other._bounds[1]  // x: right, y: top, z: near
 | 
			
		||||
 | 
			
		||||
@ -51,8 +51,8 @@ struct AABB {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extension AABB {
 | 
			
		||||
  static func + (lhs: Self, rhs: SIMD3<Float>) -> Self {
 | 
			
		||||
public extension AABB {
 | 
			
		||||
  public static func + (lhs: Self, rhs: SIMD3<Float>) -> Self {
 | 
			
		||||
    .init(bounds: lhs._bounds + .init(rhs, rhs))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -22,11 +22,13 @@ public extension SIMD3 {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public extension SIMD3 where Scalar: FloatingPoint {
 | 
			
		||||
  @inline(__always) static var X: Self      { Self(1, 0, 0) }
 | 
			
		||||
  @inline(__always) static var Y: Self      { Self(0, 1, 0) }
 | 
			
		||||
  @inline(__always) static var Z: Self      { Self(0, 0, 1) }
 | 
			
		||||
public extension SIMD3 where Scalar: Numeric {
 | 
			
		||||
  @inline(__always) static var X: Self { Self(1, 0, 0) }
 | 
			
		||||
  @inline(__always) static var Y: Self { Self(0, 1, 0) }
 | 
			
		||||
  @inline(__always) static var Z: Self { Self(0, 0, 1) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public extension SIMD3 where Scalar: FloatingPoint {
 | 
			
		||||
  @inline(__always) static var up: Self      {  Y }
 | 
			
		||||
  @inline(__always) static var down: Self    { -Y }
 | 
			
		||||
  @inline(__always) static var left: Self    { -X }
 | 
			
		||||
@ -35,6 +37,15 @@ public extension SIMD3 where Scalar: FloatingPoint {
 | 
			
		||||
  @inline(__always) static var back: Self    {  Z }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public extension SIMD3 where Scalar: SignedInteger & FixedWidthInteger {
 | 
			
		||||
  @inline(__always) static var up: Self      {      Y }
 | 
			
		||||
  @inline(__always) static var down: Self    { 0 &- Y }
 | 
			
		||||
  @inline(__always) static var left: Self    { 0 &- X }
 | 
			
		||||
  @inline(__always) static var right: Self   {      X }
 | 
			
		||||
  @inline(__always) static var forward: Self { 0 &- Z }
 | 
			
		||||
  @inline(__always) static var back: Self    {      Z }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public extension SIMD3 where Scalar: Numeric & AdditiveArithmetic {
 | 
			
		||||
  @inline(__always) func dot(_ b: Self) -> Scalar { self.x * b.x + self.y * b.y + self.z * b.z }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -90,12 +90,12 @@ public enum RaycastSide {
 | 
			
		||||
public extension SIMD3 where Scalar == Int {
 | 
			
		||||
  func offset(by side: RaycastSide) -> Self {
 | 
			
		||||
    let ofs: Self = switch side {
 | 
			
		||||
    case .right: .init( 1,  0,  0)
 | 
			
		||||
    case .left:  .init(-1,  0,  0)
 | 
			
		||||
    case .up:    .init( 0,  1,  0)
 | 
			
		||||
    case .down:  .init( 0, -1,  0)
 | 
			
		||||
    case .back:  .init( 0,  0,  1)
 | 
			
		||||
    case .front: .init( 0,  0, -1)
 | 
			
		||||
    case .right: .right
 | 
			
		||||
    case .left:  .left
 | 
			
		||||
    case .up:    .up
 | 
			
		||||
    case .down:  .down
 | 
			
		||||
    case .back:  .back
 | 
			
		||||
    case .front: .forward
 | 
			
		||||
    }
 | 
			
		||||
    return self &+ ofs
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								Sources/Voxelotl/Renderer/Mesh.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								Sources/Voxelotl/Renderer/Mesh.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
public struct Mesh<VertexType: Vertex, IndexType: UnsignedInteger> {
 | 
			
		||||
  public let vertices: [VertexType]
 | 
			
		||||
  public let indices: [IndexType]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public extension Mesh {
 | 
			
		||||
  static var empty: Self { .init(vertices: .init(), indices: .init()) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public protocol Vertex: Equatable {}
 | 
			
		||||
 | 
			
		||||
public struct VertexPositionNormalTexcoord: Vertex {
 | 
			
		||||
  var position: SIMD3<Float>
 | 
			
		||||
  var normal:   SIMD3<Float>
 | 
			
		||||
  var texCoord: SIMD2<Float>
 | 
			
		||||
}
 | 
			
		||||
@ -4,42 +4,6 @@ import QuartzCore.CAMetalLayer
 | 
			
		||||
import simd
 | 
			
		||||
import ShaderTypes
 | 
			
		||||
 | 
			
		||||
fileprivate let cubeVertices: [ShaderVertex] = [
 | 
			
		||||
  .init(position: .init(-1, -1,  1), normal: .back,    texCoord: .init(0, 0)),
 | 
			
		||||
  .init(position: .init( 1, -1,  1), normal: .back,    texCoord: .init(1, 0)),
 | 
			
		||||
  .init(position: .init(-1,  1,  1), normal: .back,    texCoord: .init(0, 1)),
 | 
			
		||||
  .init(position: .init( 1,  1,  1), normal: .back,    texCoord: .init(1, 1)),
 | 
			
		||||
  .init(position: .init( 1, -1,  1), normal: .right,   texCoord: .init(0, 0)),
 | 
			
		||||
  .init(position: .init( 1, -1, -1), normal: .right,   texCoord: .init(1, 0)),
 | 
			
		||||
  .init(position: .init( 1,  1,  1), normal: .right,   texCoord: .init(0, 1)),
 | 
			
		||||
  .init(position: .init( 1,  1, -1), normal: .right,   texCoord: .init(1, 1)),
 | 
			
		||||
  .init(position: .init( 1, -1, -1), normal: .forward, texCoord: .init(0, 0)),
 | 
			
		||||
  .init(position: .init(-1, -1, -1), normal: .forward, texCoord: .init(1, 0)),
 | 
			
		||||
  .init(position: .init( 1,  1, -1), normal: .forward, texCoord: .init(0, 1)),
 | 
			
		||||
  .init(position: .init(-1,  1, -1), normal: .forward, texCoord: .init(1, 1)),
 | 
			
		||||
  .init(position: .init(-1, -1, -1), normal: .left,    texCoord: .init(0, 0)),
 | 
			
		||||
  .init(position: .init(-1, -1,  1), normal: .left,    texCoord: .init(1, 0)),
 | 
			
		||||
  .init(position: .init(-1,  1, -1), normal: .left,    texCoord: .init(0, 1)),
 | 
			
		||||
  .init(position: .init(-1,  1,  1), normal: .left,    texCoord: .init(1, 1)),
 | 
			
		||||
  .init(position: .init(-1, -1, -1), normal: .down,    texCoord: .init(0, 0)),
 | 
			
		||||
  .init(position: .init( 1, -1, -1), normal: .down,    texCoord: .init(1, 0)),
 | 
			
		||||
  .init(position: .init(-1, -1,  1), normal: .down,    texCoord: .init(0, 1)),
 | 
			
		||||
  .init(position: .init( 1, -1,  1), normal: .down,    texCoord: .init(1, 1)),
 | 
			
		||||
  .init(position: .init(-1,  1,  1), normal: .up,      texCoord: .init(0, 0)),
 | 
			
		||||
  .init(position: .init( 1,  1,  1), normal: .up,      texCoord: .init(1, 0)),
 | 
			
		||||
  .init(position: .init(-1,  1, -1), normal: .up,      texCoord: .init(0, 1)),
 | 
			
		||||
  .init(position: .init( 1,  1, -1), normal: .up,      texCoord: .init(1, 1)),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
fileprivate let cubeIndices: [UInt16] = [
 | 
			
		||||
   0,  1,  2,  2,  1,  3,
 | 
			
		||||
   4,  5,  6,  6,  5,  7,
 | 
			
		||||
   8,  9, 10, 10,  9, 11,
 | 
			
		||||
  12, 13, 14, 14, 13, 15,
 | 
			
		||||
  16, 17, 18, 18, 17, 19,
 | 
			
		||||
  20, 21, 22, 22, 21, 23
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
fileprivate let numFramesInFlight: Int = 3
 | 
			
		||||
fileprivate let colorFormat: MTLPixelFormat = .bgra8Unorm_srgb
 | 
			
		||||
fileprivate let depthFormat: MTLPixelFormat = .depth32Float
 | 
			
		||||
@ -61,7 +25,6 @@ public class Renderer {
 | 
			
		||||
 | 
			
		||||
  private var _encoder: MTLRenderCommandEncoder! = nil
 | 
			
		||||
 | 
			
		||||
  private var vtxBuffer: MTLBuffer, idxBuffer: MTLBuffer
 | 
			
		||||
  private var defaultTexture: MTLTexture
 | 
			
		||||
  private var cubeTexture: MTLTexture? = nil
 | 
			
		||||
 | 
			
		||||
@ -150,24 +113,6 @@ public class Renderer {
 | 
			
		||||
      throw RendererError.initFailure("Failed to create pipeline state: \(error.localizedDescription)")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Create cube mesh buffers
 | 
			
		||||
    guard let vtxBuffer = device.makeBuffer(
 | 
			
		||||
      bytes: cubeVertices,
 | 
			
		||||
      length: cubeVertices.count * MemoryLayout<ShaderVertex>.stride,
 | 
			
		||||
      options: .storageModeManaged)
 | 
			
		||||
    else {
 | 
			
		||||
      throw RendererError.initFailure("Failed to create vertex buffer")
 | 
			
		||||
    }
 | 
			
		||||
    self.vtxBuffer = vtxBuffer
 | 
			
		||||
    guard let idxBuffer = device.makeBuffer(
 | 
			
		||||
      bytes: cubeIndices,
 | 
			
		||||
      length: cubeIndices.count * MemoryLayout<UInt16>.stride,
 | 
			
		||||
      options: .storageModeManaged)
 | 
			
		||||
    else {
 | 
			
		||||
      throw RendererError.initFailure("Failed to create index buffer")
 | 
			
		||||
    }
 | 
			
		||||
    self.idxBuffer = idxBuffer
 | 
			
		||||
 | 
			
		||||
    // Create a default texture
 | 
			
		||||
    do {
 | 
			
		||||
      self.defaultTexture = try Self.loadTexture(device, queue, image2D: Image2D(Data([
 | 
			
		||||
@ -192,6 +137,29 @@ public class Renderer {
 | 
			
		||||
    
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  func createMesh(_ mesh: Mesh<VertexPositionNormalTexcoord, UInt16>) -> RendererMesh? {
 | 
			
		||||
    let vertices = mesh.vertices.map {
 | 
			
		||||
      ShaderVertex(position: $0.position, normal: $0.normal, texCoord: $0.texCoord)
 | 
			
		||||
    }
 | 
			
		||||
    guard let vtxBuffer = self.device.makeBuffer(
 | 
			
		||||
      bytes: vertices,
 | 
			
		||||
      length: vertices.count * MemoryLayout<ShaderVertex>.stride,
 | 
			
		||||
      options: .storageModeManaged)
 | 
			
		||||
    else {
 | 
			
		||||
      printErr("Failed to create vertex buffer")
 | 
			
		||||
      return nil
 | 
			
		||||
    }
 | 
			
		||||
    guard let idxBuffer = device.makeBuffer(
 | 
			
		||||
      bytes: mesh.indices,
 | 
			
		||||
      length: mesh.indices.count * MemoryLayout<UInt16>.stride,
 | 
			
		||||
      options: .storageModeManaged)
 | 
			
		||||
    else {
 | 
			
		||||
      printErr("Failed to create index buffer")
 | 
			
		||||
      return nil
 | 
			
		||||
    }
 | 
			
		||||
    return .init(_vertBuf: vtxBuffer, _idxBuf: idxBuffer, numIndices: mesh.indices.count)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static func loadTexture(_ device: MTLDevice, _ queue: MTLCommandQueue, resourcePath path: String) throws -> MTLTexture {
 | 
			
		||||
    do {
 | 
			
		||||
      return try loadTexture(device, queue, url: Bundle.main.getResource(path))
 | 
			
		||||
@ -329,7 +297,6 @@ public class Renderer {
 | 
			
		||||
      encoder.setRenderPipelineState(pso)
 | 
			
		||||
      encoder.setDepthStencilState(depthStencilState)
 | 
			
		||||
      encoder.setFragmentTexture(cubeTexture ?? defaultTexture, index: 0)
 | 
			
		||||
      encoder.setVertexBuffer(vtxBuffer, offset: 0, index: VertexShaderInputIdx.vertices.rawValue)
 | 
			
		||||
 | 
			
		||||
      self._encoder = encoder
 | 
			
		||||
      frameFunc(self)
 | 
			
		||||
@ -346,7 +313,7 @@ public class Renderer {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  func batch(instances: [Instance], material: Material, environment: Environment, camera: Camera) {
 | 
			
		||||
  func batch(instances: [Instance], mesh: RendererMesh, material: Material, environment: Environment, camera: Camera) {
 | 
			
		||||
    assert(self._encoder != nil, "batch can't be called outside of a frame being rendered")
 | 
			
		||||
 | 
			
		||||
    var vertUniforms = VertexShaderUniforms(projView: camera.viewProjection)
 | 
			
		||||
@ -391,6 +358,7 @@ public class Renderer {
 | 
			
		||||
 | 
			
		||||
    self._encoder.setCullMode(.init(environment.cullFace))
 | 
			
		||||
 | 
			
		||||
    self._encoder.setVertexBuffer(mesh._vertBuf, offset: 0, index: VertexShaderInputIdx.vertices.rawValue)
 | 
			
		||||
    self._encoder.setVertexBuffer(instanceBuffer,
 | 
			
		||||
      offset: 0,
 | 
			
		||||
      index: VertexShaderInputIdx.instance.rawValue)
 | 
			
		||||
@ -404,14 +372,20 @@ public class Renderer {
 | 
			
		||||
 | 
			
		||||
    self._encoder.drawIndexedPrimitives(
 | 
			
		||||
      type: .triangle,
 | 
			
		||||
      indexCount: cubeIndices.count,
 | 
			
		||||
      indexCount: mesh.numIndices,
 | 
			
		||||
      indexType: .uint16,
 | 
			
		||||
      indexBuffer: idxBuffer,
 | 
			
		||||
      indexBuffer: mesh._idxBuf,
 | 
			
		||||
      indexBufferOffset: 0,
 | 
			
		||||
      instanceCount: numInstances)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public struct RendererMesh {
 | 
			
		||||
  fileprivate let _vertBuf: MTLBuffer
 | 
			
		||||
  fileprivate let _idxBuf: MTLBuffer
 | 
			
		||||
  public let numIndices: Int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extension MTLClearColor {
 | 
			
		||||
  init(_ color: Color<Double>) {
 | 
			
		||||
    self.init(red: color.r, green: color.g, blue: color.b, alpha: color.a)
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,16 @@ public class World {
 | 
			
		||||
    self._chunks[position &>> Chunk.shift]?.setBlock(at: position, type: type)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  func getChunk(id chunkID: SIMD3<Int>) -> Chunk? {
 | 
			
		||||
    self._chunks[chunkID]
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public func forEachChunk(_ body: @escaping (_ id: SIMD3<Int>, _ chunk: Chunk) throws -> Void) rethrows {
 | 
			
		||||
    for i in self._chunks {
 | 
			
		||||
      try body(i.key, i.value)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  func generate(width: Int, height: Int, depth: Int, seed: UInt64) {
 | 
			
		||||
    self._generator.reset(seed: seed)
 | 
			
		||||
    let orig = SIMD3(width, height, depth) / 2
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user