diff --git a/Sources/Voxelotl/Renderer/Material.swift b/Sources/Voxelotl/Renderer/Material.swift index 858dfba..a6b11a3 100644 --- a/Sources/Voxelotl/Renderer/Material.swift +++ b/Sources/Voxelotl/Renderer/Material.swift @@ -1,5 +1,4 @@ - -public struct Material { +public struct Material: Hashable { public var ambient: Color public var diffuse: Color public var specular: Color diff --git a/Sources/Voxelotl/Renderer/ModelBatch.swift b/Sources/Voxelotl/Renderer/ModelBatch.swift index d12df11..c351a51 100644 --- a/Sources/Voxelotl/Renderer/ModelBatch.swift +++ b/Sources/Voxelotl/Renderer/ModelBatch.swift @@ -5,35 +5,67 @@ public struct ModelBatch { private var _active = false private var _cam: Camera! private var _env: Environment! + private var _prev: ModelInstance! + private var _instances: [Instance] internal init(_ renderer: Renderer) { self._renderer = renderer + self._instances = Array() } //TODO: Sort, Blend - mutating func begin(camera: Camera, environment: Environment) { + public mutating func begin(camera: Camera, environment: Environment) { self._active = true self._cam = camera self._env = environment + self._prev = nil } - mutating func end() { + private mutating func flush() { + assert(self._instances.count > 0) + if self._instances.count == 1 { + let instance = self._instances.first! + self._renderer.draw( + model: instance.world, + color: instance.color, + mesh: self._prev.mesh, + material: self._prev.material, + environment: self._env, + camera: self._cam) + } else { + self._renderer.batch( + instances: self._instances, + mesh: self._prev.mesh, + material: self._prev.material, + environment: self._env, + camera: self._cam) + } + self._instances.removeAll(keepingCapacity: true) + self._prev = nil + } + + public mutating func end() { + if !self._instances.isEmpty { + self.flush() + } + self._cam = nil + self._env = nil self._active = false } - mutating func draw(_ model: ModelInstance, position: SIMD3, color: Color = .white + public mutating func draw(_ model: ModelInstance, position: SIMD3, color: Color = .white ) { self.draw(model, world: .translate(position), color: color) } - mutating func draw(_ model: ModelInstance, + public mutating func draw(_ model: ModelInstance, position: SIMD3, scale: Float, rotation: simd_quatf, color: Color = .white ) { self.draw(model, position: position, scale: .init(repeating: scale), rotation: rotation, color: color) } - mutating func draw(_ model: ModelInstance, + public mutating func draw(_ model: ModelInstance, position: SIMD3, scale: SIMD3, rotation: simd_quatf, color: Color = .white ) { @@ -44,30 +76,33 @@ public struct ModelBatch { self.draw(model, world: world, color: color) } - mutating func draw(_ model: ModelInstance, world: simd_float4x4, color: Color = .white) { + public mutating func draw(_ model: ModelInstance, world: simd_float4x4, color: Color = .white) { assert(self._active) - self._renderer.draw( - model: world, - color: color.linear, - mesh: model.mesh, - material: model.material, - environment: self._env, - camera: self._cam) + if self._prev == nil { + self._prev = model + } else if model != self._prev { + self.flush() + self._prev = model + } + + self._instances.append(.init( + world: world, + color: color.linear)) } internal struct Instance { - let model: simd_float4x4 + let world: simd_float4x4 let color: Color - init(model: simd_float4x4, color: Color = .white) { - self.model = model + init(world: simd_float4x4, color: Color = .white) { + self.world = world self.color = color } } } //TODO: delet -public struct ModelInstance { +public struct ModelInstance: Hashable { let mesh: RendererMesh let material: Material } diff --git a/Sources/Voxelotl/Renderer/Renderer.swift b/Sources/Voxelotl/Renderer/Renderer.swift index c88db76..52a9fe7 100644 --- a/Sources/Voxelotl/Renderer/Renderer.swift +++ b/Sources/Voxelotl/Renderer/Renderer.swift @@ -452,8 +452,8 @@ public class Renderer { for i in 0.. Bool { + lhs._vertBuf.gpuAddress == rhs._vertBuf.gpuAddress && lhs._vertBuf.length == rhs._vertBuf.length && + lhs._vertBuf.gpuAddress == rhs._vertBuf.gpuAddress && lhs._vertBuf.length == rhs._vertBuf.length && + lhs.numIndices == rhs.numIndices + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(self._vertBuf.hash) + hasher.combine(self._idxBuf.hash) + hasher.combine(self.numIndices) + } } extension MTLClearColor {