mirror of
				https://github.com/GayPizzaSpecifications/voxelotl-engine.git
				synced 2025-11-04 10:59:39 +00:00 
			
		
		
		
	un-hardcode various render properties (environment, material)
This commit is contained in:
		@ -57,6 +57,8 @@ public class Application {
 | 
				
			|||||||
      printErr("Renderer init error: unexpected error")
 | 
					      printErr("Renderer init error: unexpected error")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self.del.create(renderer!)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    lastCounter = SDL_GetPerformanceCounter()
 | 
					    lastCounter = SDL_GetPerformanceCounter()
 | 
				
			||||||
    return .running
 | 
					    return .running
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -26,6 +26,11 @@ add_executable(Voxelotl MACOSX_BUNDLE
 | 
				
			|||||||
  # Resource classes
 | 
					  # Resource classes
 | 
				
			||||||
  NSImageLoader.swift
 | 
					  NSImageLoader.swift
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Renderer classes
 | 
				
			||||||
 | 
					  Renderer/Material.swift
 | 
				
			||||||
 | 
					  Renderer/Environment.swift
 | 
				
			||||||
 | 
					  Renderer/Renderer.swift
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Input wrappers
 | 
					  # Input wrappers
 | 
				
			||||||
  Input/Keyboard.swift
 | 
					  Input/Keyboard.swift
 | 
				
			||||||
  Input/GameController.swift
 | 
					  Input/GameController.swift
 | 
				
			||||||
@ -34,7 +39,6 @@ add_executable(Voxelotl MACOSX_BUNDLE
 | 
				
			|||||||
  # Core utility classes
 | 
					  # Core utility classes
 | 
				
			||||||
  Color.swift
 | 
					  Color.swift
 | 
				
			||||||
  Camera.swift
 | 
					  Camera.swift
 | 
				
			||||||
  Renderer.swift
 | 
					 | 
				
			||||||
  FPSCalculator.swift
 | 
					  FPSCalculator.swift
 | 
				
			||||||
  GameDelegate.swift
 | 
					  GameDelegate.swift
 | 
				
			||||||
  Application.swift
 | 
					  Application.swift
 | 
				
			||||||
@ -85,3 +89,4 @@ source_group("Source Files" REGULAR_EXPRESSION "\\.(swift|metal)$")
 | 
				
			|||||||
source_group("Source Files\\Random" REGULAR_EXPRESSION "Random/")
 | 
					source_group("Source Files\\Random" REGULAR_EXPRESSION "Random/")
 | 
				
			||||||
source_group("Source Files\\Math" REGULAR_EXPRESSION "Math/")
 | 
					source_group("Source Files\\Math" REGULAR_EXPRESSION "Math/")
 | 
				
			||||||
source_group("Source Files\\Input" REGULAR_EXPRESSION "Input/")
 | 
					source_group("Source Files\\Input" REGULAR_EXPRESSION "Input/")
 | 
				
			||||||
 | 
					source_group("Source Files\\Renderer" REGULAR_EXPRESSION "Renderer/")
 | 
				
			||||||
 | 
				
			|||||||
@ -26,9 +26,11 @@ class Game: GameDelegate {
 | 
				
			|||||||
  var projection: matrix_float4x4 = .identity
 | 
					  var projection: matrix_float4x4 = .identity
 | 
				
			||||||
  var chunk = Chunk(position: .zero)
 | 
					  var chunk = Chunk(position: .zero)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  init() {
 | 
					  func create(_ renderer: Renderer) {
 | 
				
			||||||
    self.resetPlayer()
 | 
					    self.resetPlayer()
 | 
				
			||||||
    self.generateWorld()
 | 
					    self.generateWorld()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    renderer.clearColor = Color<Double>.black.mix(.white, 0.1).linear
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private func resetPlayer() {
 | 
					  private func resetPlayer() {
 | 
				
			||||||
@ -103,6 +105,15 @@ class Game: GameDelegate {
 | 
				
			|||||||
  func draw(_ renderer: Renderer, _ time: GameTime) {
 | 
					  func draw(_ renderer: Renderer, _ time: GameTime) {
 | 
				
			||||||
    let totalTime = Float(time.total.asFloat)
 | 
					    let totalTime = Float(time.total.asFloat)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let env = Environment(
 | 
				
			||||||
 | 
					      cullFace: .back,
 | 
				
			||||||
 | 
					      lightDirection: .init(0.75, -1, 0.5))
 | 
				
			||||||
 | 
					    let material = Material(
 | 
				
			||||||
 | 
					      ambient:  Color(rgba8888: 0x4F4F4F00).linear,
 | 
				
			||||||
 | 
					      diffuse:  Color(rgba8888: 0xDFDFDF00).linear,
 | 
				
			||||||
 | 
					      specular: Color(rgba8888: 0x2F2F2F00).linear,
 | 
				
			||||||
 | 
					      gloss: 75)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var instances = chunk.compactMap { block, position in
 | 
					    var instances = chunk.compactMap { block, position in
 | 
				
			||||||
      if case let .solid(color) = block.type {
 | 
					      if case let .solid(color) = block.type {
 | 
				
			||||||
        Instance(
 | 
					        Instance(
 | 
				
			||||||
@ -121,7 +132,7 @@ class Game: GameDelegate {
 | 
				
			|||||||
          .init(angle: totalTime * 0.7, axis: .init(0, 0, 1)),
 | 
					          .init(angle: totalTime * 0.7, axis: .init(0, 0, 1)),
 | 
				
			||||||
        color:    .init(r: 0.5, g: 0.5, b: 1).linear))
 | 
					        color:    .init(r: 0.5, g: 0.5, b: 1).linear))
 | 
				
			||||||
    if !instances.isEmpty {
 | 
					    if !instances.isEmpty {
 | 
				
			||||||
      renderer.batch(instances: instances, camera: self.camera)
 | 
					      renderer.batch(instances: instances, material: material, environment: env, camera: self.camera)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
public protocol GameDelegate {
 | 
					public protocol GameDelegate {
 | 
				
			||||||
 | 
					  func create(_ renderer: Renderer)
 | 
				
			||||||
  func fixedUpdate(_ time: GameTime)
 | 
					  func fixedUpdate(_ time: GameTime)
 | 
				
			||||||
  func update(_ time: GameTime)
 | 
					  func update(_ time: GameTime)
 | 
				
			||||||
  func draw(_ renderer: Renderer, _ time: GameTime)
 | 
					  func draw(_ renderer: Renderer, _ time: GameTime)
 | 
				
			||||||
 | 
				
			|||||||
@ -203,7 +203,7 @@ struct Player {
 | 
				
			|||||||
      chunk: chunk,
 | 
					      chunk: chunk,
 | 
				
			||||||
      origin: self.eyePosition,
 | 
					      origin: self.eyePosition,
 | 
				
			||||||
      direction: .forward * simd_matrix3x3(self.eyeRotation),
 | 
					      direction: .forward * simd_matrix3x3(self.eyeRotation),
 | 
				
			||||||
      maxDistance: 3.666
 | 
					      maxDistance: 3.8
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
      self.rayhitPos = hit.position
 | 
					      self.rayhitPos = hit.position
 | 
				
			||||||
      if destroy {
 | 
					      if destroy {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										6
									
								
								Sources/Voxelotl/Renderer/Environment.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Sources/Voxelotl/Renderer/Environment.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					public struct Environment {
 | 
				
			||||||
 | 
					  public var cullFace: Face
 | 
				
			||||||
 | 
					  public var lightDirection: SIMD3<Float>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public enum Face { case none, front, back }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								Sources/Voxelotl/Renderer/Material.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Sources/Voxelotl/Renderer/Material.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					public struct Material {
 | 
				
			||||||
 | 
					  public var ambient: Color<Float16>
 | 
				
			||||||
 | 
					  public var diffuse: Color<Float16>
 | 
				
			||||||
 | 
					  public var specular: Color<Float16>
 | 
				
			||||||
 | 
					  public var gloss: Float
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -5,30 +5,30 @@ import simd
 | 
				
			|||||||
import ShaderTypes
 | 
					import ShaderTypes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fileprivate let cubeVertices: [ShaderVertex] = [
 | 
					fileprivate let cubeVertices: [ShaderVertex] = [
 | 
				
			||||||
  .init(position: .init(-1, -1,  1, 1), normal: .init( 0,  0,  1,  0), texCoord: .init(0, 0)),
 | 
					  .init(position: .init(-1, -1,  1, 1), normal: .init(.back,    0), texCoord: .init(0, 0)),
 | 
				
			||||||
  .init(position: .init( 1, -1,  1, 1), normal: .init( 0,  0,  1,  0), texCoord: .init(1, 0)),
 | 
					  .init(position: .init( 1, -1,  1, 1), normal: .init(.back,    0), texCoord: .init(1, 0)),
 | 
				
			||||||
  .init(position: .init(-1,  1,  1, 1), normal: .init( 0,  0,  1,  0), texCoord: .init(0, 1)),
 | 
					  .init(position: .init(-1,  1,  1, 1), normal: .init(.back,    0), texCoord: .init(0, 1)),
 | 
				
			||||||
  .init(position: .init( 1,  1,  1, 1), normal: .init( 0,  0,  1,  0), texCoord: .init(1, 1)),
 | 
					  .init(position: .init( 1,  1,  1, 1), normal: .init(.back,    0), texCoord: .init(1, 1)),
 | 
				
			||||||
  .init(position: .init( 1, -1,  1, 1), normal: .init( 1,  0,  0,  0), texCoord: .init(0, 0)),
 | 
					  .init(position: .init( 1, -1,  1, 1), normal: .init(.right,   0), texCoord: .init(0, 0)),
 | 
				
			||||||
  .init(position: .init( 1, -1, -1, 1), normal: .init( 1,  0,  0,  0), texCoord: .init(1, 0)),
 | 
					  .init(position: .init( 1, -1, -1, 1), normal: .init(.right,   0), texCoord: .init(1, 0)),
 | 
				
			||||||
  .init(position: .init( 1,  1,  1, 1), normal: .init( 1,  0,  0,  0), texCoord: .init(0, 1)),
 | 
					  .init(position: .init( 1,  1,  1, 1), normal: .init(.right,   0), texCoord: .init(0, 1)),
 | 
				
			||||||
  .init(position: .init( 1,  1, -1, 1), normal: .init( 1,  0,  0,  0), texCoord: .init(1, 1)),
 | 
					  .init(position: .init( 1,  1, -1, 1), normal: .init(.right,   0), texCoord: .init(1, 1)),
 | 
				
			||||||
  .init(position: .init( 1, -1, -1, 1), normal: .init( 0,  0, -1,  0), texCoord: .init(0, 0)),
 | 
					  .init(position: .init( 1, -1, -1, 1), normal: .init(.forward, 0), texCoord: .init(0, 0)),
 | 
				
			||||||
  .init(position: .init(-1, -1, -1, 1), normal: .init( 0,  0, -1,  0), texCoord: .init(1, 0)),
 | 
					  .init(position: .init(-1, -1, -1, 1), normal: .init(.forward, 0), texCoord: .init(1, 0)),
 | 
				
			||||||
  .init(position: .init( 1,  1, -1, 1), normal: .init( 0,  0, -1,  0), texCoord: .init(0, 1)),
 | 
					  .init(position: .init( 1,  1, -1, 1), normal: .init(.forward, 0), texCoord: .init(0, 1)),
 | 
				
			||||||
  .init(position: .init(-1,  1, -1, 1), normal: .init( 0,  0, -1,  0), texCoord: .init(1, 1)),
 | 
					  .init(position: .init(-1,  1, -1, 1), normal: .init(.forward, 0), texCoord: .init(1, 1)),
 | 
				
			||||||
  .init(position: .init(-1, -1, -1, 1), normal: .init(-1,  0,  0,  0), texCoord: .init(0, 0)),
 | 
					  .init(position: .init(-1, -1, -1, 1), normal: .init(.left,    0), texCoord: .init(0, 0)),
 | 
				
			||||||
  .init(position: .init(-1, -1,  1, 1), normal: .init(-1,  0,  0,  0), texCoord: .init(1, 0)),
 | 
					  .init(position: .init(-1, -1,  1, 1), normal: .init(.left,    0), texCoord: .init(1, 0)),
 | 
				
			||||||
  .init(position: .init(-1,  1, -1, 1), normal: .init(-1,  0,  0,  0), texCoord: .init(0, 1)),
 | 
					  .init(position: .init(-1,  1, -1, 1), normal: .init(.left,    0), texCoord: .init(0, 1)),
 | 
				
			||||||
  .init(position: .init(-1,  1,  1, 1), normal: .init(-1,  0,  0,  0), texCoord: .init(1, 1)),
 | 
					  .init(position: .init(-1,  1,  1, 1), normal: .init(.left,    0), texCoord: .init(1, 1)),
 | 
				
			||||||
  .init(position: .init(-1, -1, -1, 1), normal: .init( 0, -1,  0,  0), texCoord: .init(0, 0)),
 | 
					  .init(position: .init(-1, -1, -1, 1), normal: .init(.down,    0), texCoord: .init(0, 0)),
 | 
				
			||||||
  .init(position: .init( 1, -1, -1, 1), normal: .init( 0, -1,  0,  0), texCoord: .init(1, 0)),
 | 
					  .init(position: .init( 1, -1, -1, 1), normal: .init(.down,    0), texCoord: .init(1, 0)),
 | 
				
			||||||
  .init(position: .init(-1, -1,  1, 1), normal: .init( 0, -1,  0,  0), texCoord: .init(0, 1)),
 | 
					  .init(position: .init(-1, -1,  1, 1), normal: .init(.down,    0), texCoord: .init(0, 1)),
 | 
				
			||||||
  .init(position: .init( 1, -1,  1, 1), normal: .init( 0, -1,  0,  0), texCoord: .init(1, 1)),
 | 
					  .init(position: .init( 1, -1,  1, 1), normal: .init(.down,    0), texCoord: .init(1, 1)),
 | 
				
			||||||
  .init(position: .init(-1,  1,  1, 1), normal: .init( 0,  1,  0,  0), texCoord: .init(0, 0)),
 | 
					  .init(position: .init(-1,  1,  1, 1), normal: .init(.up,      0), texCoord: .init(0, 0)),
 | 
				
			||||||
  .init(position: .init( 1,  1,  1, 1), normal: .init( 0,  1,  0,  0), texCoord: .init(1, 0)),
 | 
					  .init(position: .init( 1,  1,  1, 1), normal: .init(.up,      0), texCoord: .init(1, 0)),
 | 
				
			||||||
  .init(position: .init(-1,  1, -1, 1), normal: .init( 0,  1,  0,  0), texCoord: .init(0, 1)),
 | 
					  .init(position: .init(-1,  1, -1, 1), normal: .init(.up,      0), texCoord: .init(0, 1)),
 | 
				
			||||||
  .init(position: .init( 1,  1, -1, 1), normal: .init( 0,  1,  0,  0), texCoord: .init(1, 1)),
 | 
					  .init(position: .init( 1,  1, -1, 1), normal: .init(.up,      0), texCoord: .init(1, 1)),
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fileprivate let cubeIndices: [UInt16] = [
 | 
					fileprivate let cubeIndices: [UInt16] = [
 | 
				
			||||||
@ -43,12 +43,12 @@ fileprivate let cubeIndices: [UInt16] = [
 | 
				
			|||||||
fileprivate let numFramesInFlight: Int = 3
 | 
					fileprivate let numFramesInFlight: Int = 3
 | 
				
			||||||
fileprivate let colorFormat: MTLPixelFormat = .bgra8Unorm_srgb
 | 
					fileprivate let colorFormat: MTLPixelFormat = .bgra8Unorm_srgb
 | 
				
			||||||
fileprivate let depthFormat: MTLPixelFormat = .depth32Float
 | 
					fileprivate let depthFormat: MTLPixelFormat = .depth32Float
 | 
				
			||||||
fileprivate let clearColor: Color<Double> = .black.mix(.white, 0.1).linear
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class Renderer {
 | 
					public class Renderer {
 | 
				
			||||||
  private var device: MTLDevice
 | 
					  private var device: MTLDevice
 | 
				
			||||||
  private var layer: CAMetalLayer
 | 
					  private var layer: CAMetalLayer
 | 
				
			||||||
  private var backBufferSize: Size<Int>
 | 
					  private var backBufferSize: Size<Int>
 | 
				
			||||||
 | 
					  private var _clearColor: Color<Double>
 | 
				
			||||||
  private var _aspectRatio: Float
 | 
					  private var _aspectRatio: Float
 | 
				
			||||||
  private var queue: MTLCommandQueue
 | 
					  private var queue: MTLCommandQueue
 | 
				
			||||||
  private var lib: MTLLibrary
 | 
					  private var lib: MTLLibrary
 | 
				
			||||||
@ -70,6 +70,10 @@ public class Renderer {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  var frame: Rect<Int> { .init(origin: .zero, size: self.backBufferSize) }
 | 
					  var frame: Rect<Int> { .init(origin: .zero, size: self.backBufferSize) }
 | 
				
			||||||
  var aspectRatio: Float { self._aspectRatio }
 | 
					  var aspectRatio: Float { self._aspectRatio }
 | 
				
			||||||
 | 
					  var clearColor: Color<Double> {
 | 
				
			||||||
 | 
					    get { self._clearColor }
 | 
				
			||||||
 | 
					    set { self._clearColor = newValue }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fileprivate static func createMetalDevice() -> MTLDevice? {
 | 
					  fileprivate static func createMetalDevice() -> MTLDevice? {
 | 
				
			||||||
    MTLCopyAllDevices().reduce(nil, { best, dev in
 | 
					    MTLCopyAllDevices().reduce(nil, { best, dev in
 | 
				
			||||||
@ -100,10 +104,10 @@ public class Renderer {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    self.backBufferSize = size
 | 
					    self.backBufferSize = size
 | 
				
			||||||
    self._aspectRatio = Float(self.backBufferSize.w) / Float(self.backBufferSize.w)
 | 
					    self._aspectRatio = Float(self.backBufferSize.w) / Float(self.backBufferSize.w)
 | 
				
			||||||
 | 
					    self._clearColor = .black
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    passDescription.colorAttachments[0].loadAction  = .clear
 | 
					    passDescription.colorAttachments[0].loadAction  = .clear
 | 
				
			||||||
    passDescription.colorAttachments[0].storeAction = .store
 | 
					    passDescription.colorAttachments[0].storeAction = .store
 | 
				
			||||||
    passDescription.colorAttachments[0].clearColor  = MTLClearColor(clearColor)
 | 
					 | 
				
			||||||
    passDescription.depthAttachment.loadAction  = .clear
 | 
					    passDescription.depthAttachment.loadAction  = .clear
 | 
				
			||||||
    passDescription.depthAttachment.storeAction = .dontCare
 | 
					    passDescription.depthAttachment.storeAction = .dontCare
 | 
				
			||||||
    passDescription.depthAttachment.clearDepth  = 1.0
 | 
					    passDescription.depthAttachment.clearDepth  = 1.0
 | 
				
			||||||
@ -302,6 +306,7 @@ public class Renderer {
 | 
				
			|||||||
        throw RendererError.drawFailure("Failed to get next drawable render target")
 | 
					        throw RendererError.drawFailure("Failed to get next drawable render target")
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      passDescription.colorAttachments[0].clearColor  = MTLClearColor(self._clearColor)
 | 
				
			||||||
      passDescription.colorAttachments[0].texture = rt.texture
 | 
					      passDescription.colorAttachments[0].texture = rt.texture
 | 
				
			||||||
      passDescription.depthAttachment.texture = self.depthTextures[self.currentFrame]
 | 
					      passDescription.depthAttachment.texture = self.depthTextures[self.currentFrame]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -319,7 +324,6 @@ public class Renderer {
 | 
				
			|||||||
        throw RendererError.drawFailure("Failed to make render encoder from command buffer")
 | 
					        throw RendererError.drawFailure("Failed to make render encoder from command buffer")
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      encoder.setCullMode(.back)
 | 
					 | 
				
			||||||
      encoder.setFrontFacing(.counterClockwise)  // OpenGL default
 | 
					      encoder.setFrontFacing(.counterClockwise)  // OpenGL default
 | 
				
			||||||
      encoder.setViewport(Self.makeViewport(rect: self.frame))
 | 
					      encoder.setViewport(Self.makeViewport(rect: self.frame))
 | 
				
			||||||
      encoder.setRenderPipelineState(pso)
 | 
					      encoder.setRenderPipelineState(pso)
 | 
				
			||||||
@ -342,17 +346,17 @@ public class Renderer {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  func batch(instances: [Instance], camera: Camera) {
 | 
					  func batch(instances: [Instance], material: Material, environment: Environment, camera: Camera) {
 | 
				
			||||||
    assert(self._encoder != nil, "batch can't be called outside of a frame being rendered")
 | 
					    assert(self._encoder != nil, "batch can't be called outside of a frame being rendered")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var vertUniforms = VertexShaderUniforms(projView: camera.viewProjection)
 | 
					    var vertUniforms = VertexShaderUniforms(projView: camera.viewProjection)
 | 
				
			||||||
    var fragUniforms = FragmentShaderUniforms(
 | 
					    var fragUniforms = FragmentShaderUniforms(
 | 
				
			||||||
      cameraPosition: camera.position,
 | 
					      cameraPosition: camera.position,
 | 
				
			||||||
      directionalLight: normalize(.init(0.75, -1, 0.5)),
 | 
					      directionalLight: normalize(environment.lightDirection),
 | 
				
			||||||
      ambientColor:  SIMD4(Color(rgba8888: 0x1F1F1F00).linear),
 | 
					      ambientColor:  SIMD4(Color<Float>(material.ambient)),
 | 
				
			||||||
      diffuseColor:  SIMD4(Color(rgba8888: 0xEFEFEF00).linear),
 | 
					      diffuseColor:  SIMD4(Color<Float>(material.diffuse)),
 | 
				
			||||||
      specularColor: SIMD4(Color(rgba8888: 0x7F7F7F00).linear),
 | 
					      specularColor: SIMD4(Color<Float>(material.specular)),
 | 
				
			||||||
      specularIntensity: 50)
 | 
					      specularIntensity: material.gloss)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let numInstances = instances.count
 | 
					    let numInstances = instances.count
 | 
				
			||||||
    let instancesBytes = numInstances * MemoryLayout<VertexShaderInstance>.stride
 | 
					    let instancesBytes = numInstances * MemoryLayout<VertexShaderInstance>.stride
 | 
				
			||||||
@ -385,6 +389,8 @@ public class Renderer {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    instanceBuffer.didModifyRange(0..<instancesBytes)
 | 
					    instanceBuffer.didModifyRange(0..<instancesBytes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self._encoder.setCullMode(.init(environment.cullFace))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    self._encoder.setVertexBuffer(instanceBuffer,
 | 
					    self._encoder.setVertexBuffer(instanceBuffer,
 | 
				
			||||||
      offset: 0,
 | 
					      offset: 0,
 | 
				
			||||||
      index: VertexShaderInputIdx.instance.rawValue)
 | 
					      index: VertexShaderInputIdx.instance.rawValue)
 | 
				
			||||||
@ -412,6 +418,16 @@ extension MTLClearColor {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fileprivate extension MTLCullMode {
 | 
				
			||||||
 | 
					  init(_ face: Environment.Face) {
 | 
				
			||||||
 | 
					    self = switch face {
 | 
				
			||||||
 | 
					    case .none: .none
 | 
				
			||||||
 | 
					    case .front: .front
 | 
				
			||||||
 | 
					    case .back: .back
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum RendererError: Error {
 | 
					enum RendererError: Error {
 | 
				
			||||||
  case initFailure(_ message: String)
 | 
					  case initFailure(_ message: String)
 | 
				
			||||||
  case loadFailure(_ message: String)
 | 
					  case loadFailure(_ message: String)
 | 
				
			||||||
		Reference in New Issue
	
	Block a user