mirror of
				https://github.com/GayPizzaSpecifications/voxelotl-engine.git
				synced 2025-11-04 02:59:37 +00:00 
			
		
		
		
	replace darwin prng with higher quality prngs
This commit is contained in:
		@ -18,7 +18,8 @@ add_executable(Voxelotl MACOSX_BUNDLE
 | 
				
			|||||||
  Random/RandomProvider.swift
 | 
					  Random/RandomProvider.swift
 | 
				
			||||||
  Random/RandomRange.swift
 | 
					  Random/RandomRange.swift
 | 
				
			||||||
  Random/Arc4Random.swift
 | 
					  Random/Arc4Random.swift
 | 
				
			||||||
  Random/DarwinRandom.swift
 | 
					  Random/PCG32Random.swift
 | 
				
			||||||
 | 
					  Random/Xoroshiro128.swift
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Resource classes
 | 
					  # Resource classes
 | 
				
			||||||
  NSImageLoader.swift
 | 
					  NSImageLoader.swift
 | 
				
			||||||
 | 
				
			|||||||
@ -33,9 +33,15 @@ class Game: GameDelegate {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private func generateWorld() {
 | 
					  private func generateWorld() {
 | 
				
			||||||
    let newSeed = Arc4Random.instance.next(in: DarwinRandom.max)
 | 
					#if true
 | 
				
			||||||
 | 
					    let newSeed = UInt64(Arc4Random.instance.next()) | UInt64(Arc4Random.instance.next()) << 32
 | 
				
			||||||
    printErr(newSeed)
 | 
					    printErr(newSeed)
 | 
				
			||||||
    var random = DarwinRandom(seed: newSeed)
 | 
					    var random = Xoroshiro128PlusPlus(seed: newSeed)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    var random = PCG32Random(
 | 
				
			||||||
 | 
					      seed: UInt64(Arc4Random.instance.next()) | UInt64(Arc4Random.instance.next()) << 32,
 | 
				
			||||||
 | 
					      sequence: UInt64(Arc4Random.instance.next()) | UInt64(Arc4Random.instance.next()) << 32)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
    self.chunk.fill(allBy: {
 | 
					    self.chunk.fill(allBy: {
 | 
				
			||||||
      if (random.next() & 0x1) == 0x1 {
 | 
					      if (random.next() & 0x1) == 0x1 {
 | 
				
			||||||
        .solid(.init(rgb888: UInt32(random.next(in: 0..<0xFFFFFF+1))).linear)
 | 
					        .solid(.init(rgb888: UInt32(random.next(in: 0..<0xFFFFFF+1))).linear)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,33 +0,0 @@
 | 
				
			|||||||
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)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										47
									
								
								Sources/Voxelotl/Random/PCG32Random.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								Sources/Voxelotl/Random/PCG32Random.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					public struct PCG32Random: RandomProvider {
 | 
				
			||||||
 | 
					  public typealias Output = UInt32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public static var min: UInt32 { .min }
 | 
				
			||||||
 | 
					  public static var max: UInt32 { .max }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private var _state: UInt64, _inc: UInt64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public var state: (UInt64, UInt64) {
 | 
				
			||||||
 | 
					    get { (self._state, self._inc) }
 | 
				
			||||||
 | 
					    set {
 | 
				
			||||||
 | 
					      self._state = newValue.0
 | 
				
			||||||
 | 
					      self._inc   = newValue.1
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  init() {
 | 
				
			||||||
 | 
					    self._state = 0x853C49E6748FEA9B
 | 
				
			||||||
 | 
					    self._inc   = 0xDA3E39CB94B95BDB
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public init(seed: UInt64, sequence: UInt64) {
 | 
				
			||||||
 | 
					    self.init()
 | 
				
			||||||
 | 
					    self.seed(state: _state, sequence: sequence)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public mutating func seed(state: UInt64, sequence: UInt64) {
 | 
				
			||||||
 | 
					    self._state = 0
 | 
				
			||||||
 | 
					    self._inc   = sequence << 1 | 0x1
 | 
				
			||||||
 | 
					    _ = next()
 | 
				
			||||||
 | 
					    self._state &+= state
 | 
				
			||||||
 | 
					    _ = next()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public mutating func next() -> UInt32 {
 | 
				
			||||||
 | 
					    let prevState = self._state
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // LCG component
 | 
				
			||||||
 | 
					    self._state &*= 6364136223846793005
 | 
				
			||||||
 | 
					    self._state &+= self._inc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Permutation (XorShift + RotRight)
 | 
				
			||||||
 | 
					    let xorShifted = UInt32(truncatingIfNeeded: (prevState &>> 18 ^ prevState) &>> 27)
 | 
				
			||||||
 | 
					    let rot59 = UInt32(truncatingIfNeeded: prevState &>> 59)
 | 
				
			||||||
 | 
					    return xorShifted &>> rot59 | xorShifted &<< UInt32(bitPattern: -Int32(bitPattern: rot59) & 0x1F)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										126
									
								
								Sources/Voxelotl/Random/Xoroshiro128.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								Sources/Voxelotl/Random/Xoroshiro128.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,126 @@
 | 
				
			|||||||
 | 
					struct Xoroshiro128Plus: RandomProvider {
 | 
				
			||||||
 | 
					  public typealias Output = UInt64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static public var min: UInt64 { .min }
 | 
				
			||||||
 | 
					  static public var max: UInt64 { .max }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public var state: (UInt64, UInt64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public init() {
 | 
				
			||||||
 | 
					    self.state = (0, 0)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public init(state: (UInt64, UInt64)) {
 | 
				
			||||||
 | 
					    self.state = (state.0, state.1)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public init(seed: UInt64) {
 | 
				
			||||||
 | 
					    let s0 = splitMix64(seed: seed)
 | 
				
			||||||
 | 
					    self.init(state: (s0, splitMix64(seed: s0)))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public mutating func seed(_ seed: UInt64) {
 | 
				
			||||||
 | 
					    let s0 = splitMix64(seed: seed)
 | 
				
			||||||
 | 
					    self.state = (s0, splitMix64(seed: s0))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public mutating func next() -> UInt64 {
 | 
				
			||||||
 | 
					    let result = self.state.0 &+ self.state.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let xor = state.1 ^ self.state.0
 | 
				
			||||||
 | 
					    self.state = (
 | 
				
			||||||
 | 
					      self.state.0.rotate(left: 24) ^ xor ^ xor &<< 16,
 | 
				
			||||||
 | 
					      xor.rotate(left: 37))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Xoroshiro128PlusPlus: RandomProvider {
 | 
				
			||||||
 | 
					  public typealias Output = UInt64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static public var min: UInt64 { .min }
 | 
				
			||||||
 | 
					  static public var max: UInt64 { .max }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public var state: (UInt64, UInt64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public init() {
 | 
				
			||||||
 | 
					    self.state = (0, 0)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public init(state: (UInt64, UInt64)) {
 | 
				
			||||||
 | 
					    self.state = (state.0, state.1)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public init(seed: UInt64) {
 | 
				
			||||||
 | 
					    let s0 = splitMix64(seed: seed)
 | 
				
			||||||
 | 
					    self.init(state: (s0, splitMix64(seed: s0)))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public mutating func seed(_ seed: UInt64) {
 | 
				
			||||||
 | 
					    let s0 = splitMix64(seed: seed)
 | 
				
			||||||
 | 
					    self.state = (s0, splitMix64(seed: s0))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public mutating func next() -> UInt64 {
 | 
				
			||||||
 | 
					    let result = (self.state.0 &+ self.state.1).rotate(left: 17) &+ self.state.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let xor = state.1 ^ self.state.0
 | 
				
			||||||
 | 
					    self.state = (
 | 
				
			||||||
 | 
					      self.state.0.rotate(left: 49) ^ xor ^ xor << 21,
 | 
				
			||||||
 | 
					      xor.rotate(left: 28))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Xoroshiro128StarStar: RandomProvider {
 | 
				
			||||||
 | 
					  public typealias Output = UInt64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static public var min: UInt64 { .min }
 | 
				
			||||||
 | 
					  static public var max: UInt64 { .max }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public var state: (UInt64, UInt64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public init() {
 | 
				
			||||||
 | 
					    self.state = (0, 0)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public init(state: (UInt64, UInt64)) {
 | 
				
			||||||
 | 
					    self.state = (state.0, state.1)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public init(seed: UInt64) {
 | 
				
			||||||
 | 
					    let s0 = splitMix64(seed: seed)
 | 
				
			||||||
 | 
					    self.init(state: (s0, splitMix64(seed: s0)))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public mutating func seed(_ seed: UInt64) {
 | 
				
			||||||
 | 
					    let s0 = splitMix64(seed: seed)
 | 
				
			||||||
 | 
					    self.state = (s0, splitMix64(seed: s0))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public mutating func next() -> UInt64 {
 | 
				
			||||||
 | 
					    let result = (self.state.0 &* 5).rotate(left: 7) &* 9
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let xor = self.state.1 ^ self.state.0
 | 
				
			||||||
 | 
					    self.state = (
 | 
				
			||||||
 | 
					      self.state.0.rotate(left: 24) ^ xor ^ xor << 16,
 | 
				
			||||||
 | 
					      xor.rotate(left: 37))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fileprivate extension UInt64 {
 | 
				
			||||||
 | 
					  func rotate(left count: Int) -> Self {
 | 
				
			||||||
 | 
					    self &<< count | self &>> (Self.bitWidth &- count)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fileprivate func splitMix64(seed: UInt64) -> UInt64 {
 | 
				
			||||||
 | 
					  var x = seed &+ 0x9E3779B97F4A7C15
 | 
				
			||||||
 | 
					  x = (x ^ x &>> 30) &* 0xBF58476D1CE4E5B9
 | 
				
			||||||
 | 
					  x = (x ^ x &>> 27) &* 0x94D049BB133111EB
 | 
				
			||||||
 | 
					  return x ^ x &>> 31
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user