From cb2ffe78a4a189aa7605b03cbf2c8b80979291d1 Mon Sep 17 00:00:00 2001 From: a dinosaur Date: Thu, 22 Aug 2024 03:37:29 +1000 Subject: [PATCH] use arc4random to seed non-csprng, fleshes out random subsystem --- Sources/Voxelotl/CMakeLists.txt | 2 ++ Sources/Voxelotl/Game.swift | 31 ++++++++++++-------- Sources/Voxelotl/Random/Arc4Random.swift | 10 +++++-- Sources/Voxelotl/Random/DarwinRandom.swift | 33 ++++++++++++++++++++++ Sources/Voxelotl/Random/RandomRange.swift | 20 +++++++++++++ Sources/Voxelotl/Renderer.swift | 2 +- 6 files changed, 83 insertions(+), 15 deletions(-) create mode 100644 Sources/Voxelotl/Random/DarwinRandom.swift create mode 100644 Sources/Voxelotl/Random/RandomRange.swift diff --git a/Sources/Voxelotl/CMakeLists.txt b/Sources/Voxelotl/CMakeLists.txt index 3a129e7..3b762de 100644 --- a/Sources/Voxelotl/CMakeLists.txt +++ b/Sources/Voxelotl/CMakeLists.txt @@ -13,7 +13,9 @@ add_executable(Voxelotl MACOSX_BUNDLE Color.swift Random/RandomProvider.swift + Random/RandomRange.swift Random/Arc4Random.swift + Random/DarwinRandom.swift NSImageLoader.swift Renderer.swift diff --git a/Sources/Voxelotl/Game.swift b/Sources/Voxelotl/Game.swift index 174c132..113e010 100644 --- a/Sources/Voxelotl/Game.swift +++ b/Sources/Voxelotl/Game.swift @@ -25,18 +25,21 @@ class Game: GameDelegate { var player = Player() var projection: matrix_float4x4 = .identity var chunk = Chunk(position: .zero) - var random = Arc4Random.instance init() { - player.position = SIMD3(0.5, Float(Chunk.chunkSize) + 0.5, 0.5) - player.rotation = .init(.pi, 0) + self.player.position = SIMD3(0.5, Float(Chunk.chunkSize) + 0.5, 0.5) + self.player.rotation = .init(.pi, 0) + self.generateWorld() + } + private func generateWorld() { + var random = DarwinRandom(seed: Arc4Random.instance.next(in: DarwinRandom.max)) let colors: [Color] = [ .white, .red, .blue, .green, .magenta, .yellow, .cyan ] - chunk.fill(allBy: { + self.chunk.fill(allBy: { if (random.next() & 0x1) == 0x1 { .solid(colors[random.next(in: 0..) -> Int { - assert(bound.upperBound <= Self.max) - return bound.lowerBound + Int(arc4random_uniform(UInt32(bound.upperBound))) + public func next(in bound: Int) -> Int { + assert(bound <= Self.max) + return Int(arc4random_uniform(UInt32(bound))) + } + + public func next(in range: Range) -> Int { + return range.lowerBound + next(in: range.upperBound - range.lowerBound) } } diff --git a/Sources/Voxelotl/Random/DarwinRandom.swift b/Sources/Voxelotl/Random/DarwinRandom.swift new file mode 100644 index 0000000..daf30a3 --- /dev/null +++ b/Sources/Voxelotl/Random/DarwinRandom.swift @@ -0,0 +1,33 @@ +public struct DarwinRandom: RandomProvider { + public typealias Output = Int + + public static var min: Int { 0x00000000 } + public static var max: Int { 0x7FFFFFFF } + + private var state: Int + + init() { + self.state = 0 + } + + public init(seed: Int) { + self.state = seed + } + + mutating public func seed(with seed: Int) { + self.state = seed + } + + mutating public func next() -> Int { + if self.state == 0 { + self.state = 123459876 + } + let hi = self.state / 127773 + let lo = self.state - hi * 127773 + self.state = 16807 * lo - 2836 * hi + if self.state < 0 { + self.state += Self.max + } + return self.state % (Self.max + 1) + } +} diff --git a/Sources/Voxelotl/Random/RandomRange.swift b/Sources/Voxelotl/Random/RandomRange.swift new file mode 100644 index 0000000..baf5b61 --- /dev/null +++ b/Sources/Voxelotl/Random/RandomRange.swift @@ -0,0 +1,20 @@ +public extension RandomProvider where Output: BinaryInteger { + mutating func next(in range: Range) -> Int { + range.lowerBound + self.next(in: range.upperBound - range.lowerBound) + } + + mutating func next(in range: ClosedRange) -> Int { + range.lowerBound + self.next(in: range.upperBound - range.lowerBound + 1) + } + + mutating func next(in bound: Int) -> Int { + assert(Self.min == 0) + assert(Self.max >= bound) + let threshold = Int(Self.max % Output(bound)) + var result: Int + repeat { + result = Int(truncatingIfNeeded: self.next()) + } while result < threshold + return result % bound + } +} diff --git a/Sources/Voxelotl/Renderer.swift b/Sources/Voxelotl/Renderer.swift index c5d55b1..7473381 100644 --- a/Sources/Voxelotl/Renderer.swift +++ b/Sources/Voxelotl/Renderer.swift @@ -358,7 +358,7 @@ public class Renderer { let instancesBytes = numInstances * MemoryLayout.stride // (Re)create instance buffer if needed - if self._instances[self.currentFrame] == nil || numInstances > self._instances[self.currentFrame]!.length { + if self._instances[self.currentFrame] == nil || instancesBytes > self._instances[self.currentFrame]!.length { guard let instanceBuffer = self.device.makeBuffer( length: instancesBytes, options: .storageModeManaged)