diff --git a/Sources/Voxelotl/CMakeLists.txt b/Sources/Voxelotl/CMakeLists.txt index 14ed29f..5b00820 100644 --- a/Sources/Voxelotl/CMakeLists.txt +++ b/Sources/Voxelotl/CMakeLists.txt @@ -9,6 +9,7 @@ add_executable(Voxelotl MACOSX_BUNDLE # Maths library Math/FloatExtensions.swift + Math/IntegerExtensions.swift Math/VectorExtensions.swift Math/Matrix4x4.swift Math/Point.swift diff --git a/Sources/Voxelotl/Color.swift b/Sources/Voxelotl/Color.swift index 9f0e7d4..121853a 100644 --- a/Sources/Voxelotl/Color.swift +++ b/Sources/Voxelotl/Color.swift @@ -161,3 +161,37 @@ public extension SIMD4 { self = other.values } } + +public extension Color where T: FloatingPoint { + init(hue: T, saturation: T, value: T) { + if saturation == 0 { + self.init(r: value, g: value, b: value, a: 1) + } else { + let hue = hue.floorMod(360) + + let rescale: T = 1 / 60 + let interp = (hue - floor(hue * rescale) * 60) * rescale + let invInterp = (1 - interp) + + let base = 1 - saturation + + let dark = base * value + let rise = value * interp + dark * invInterp + let fall = dark * interp + value * invInterp + + if hue < 60 { + self.init(r: value, g: rise, b: dark, a: 1) + } else if hue < 120 { + self.init(r: fall, g: value, b: dark, a: 1) + } else if hue < 180 { + self.init(r: dark, g: value, b: rise, a: 1) + } else if hue < 240 { + self.init(r: dark, g: fall, b: value, a: 1) + } else if hue < 300 { + self.init(r: rise, g: dark, b: value, a: 1) + } else { + self.init(r: value, g: dark, b: fall, a: 1) + } + } + } +} diff --git a/Sources/Voxelotl/Math/FloatExtensions.swift b/Sources/Voxelotl/Math/FloatExtensions.swift index b65783b..f3095bc 100644 --- a/Sources/Voxelotl/Math/FloatExtensions.swift +++ b/Sources/Voxelotl/Math/FloatExtensions.swift @@ -10,4 +10,13 @@ public extension FloatingPoint { @inline(__always) func smoothStep() -> Self { self * self * (3 - 2 * self) } @inline(__always) func smootherStep() -> Self { self * self * self * (self * (self * 6 - 15) + 10) } + + @inline(__always) func euclidianMod(_ divisor: Self) -> Self { self.floorMod(abs(divisor)) } + @inline(__always) func floorMod(_ divisor: Self) -> Self { + //fmod(fmod(self, divisor) + divisor, divisor) + (self.truncateMod(divisor) + divisor).truncateMod(divisor) + } + @inline(__always) func truncateMod(_ divisor: Self) -> Self { + self.truncatingRemainder(dividingBy: divisor) + } } diff --git a/Sources/Voxelotl/Math/IntegerExtensions.swift b/Sources/Voxelotl/Math/IntegerExtensions.swift new file mode 100644 index 0000000..e677ef6 --- /dev/null +++ b/Sources/Voxelotl/Math/IntegerExtensions.swift @@ -0,0 +1,12 @@ +public extension BinaryInteger { + @inline(__always) func euclidianMod(_ divisor: Self) -> Self { + self.floorMod(divisor < 0 ? divisor * -1 : divisor) + } + @inline(__always) func floorMod(_ divisor: Self) -> Self { + //(self % divisor + divisor) % divisor + (self.truncateMod(divisor) + divisor).truncateMod(divisor) + } + @inline(__always) func truncateMod(_ divisor: Self) -> Self { + self.quotientAndRemainder(dividingBy: divisor).remainder + } +} diff --git a/Sources/Voxelotl/World.swift b/Sources/Voxelotl/World.swift index 21a41ff..71e5534 100644 --- a/Sources/Voxelotl/World.swift +++ b/Sources/Voxelotl/World.swift @@ -19,6 +19,7 @@ public class World { func generate(width: Int, height: Int, depth: Int, random: inout any RandomProvider) { let noise = ImprovedPerlin(random: &random) + let noise2 = SimplexNoise(random: &random) for x in 0..(position) return if fpos.y / Float(Chunk.size) + noise.get(fpos * 0.05) * 1.1 - + noise.get(fpos * 0.1 + 500) * 0.5 - + noise.get(fpos * 0.3 + 100) * 0.23 < 0.6 { + + noise.get(fpos * 0.10) * 0.5 + + noise.get(fpos * 0.30) * 0.23 < 0.6 { .solid(.init( - r: Float16(noise.get(fpos * 0.1)), - g: Float16(noise.get(fpos * 0.1 + 10)), - b: Float16(noise.get(fpos * 0.1 + 100))).mix(.white, 0.6).linear) + hue: Float16(180 + noise2.get(fpos * 0.05) * 180), + saturation: Float16(0.5 + noise2.get(SIMD4(fpos * 0.05, 4)) * 0.5), + value: Float16(0.5 + noise2.get(SIMD4(fpos * 0.05, 9)) * 0.5).lerp(0.5, 1)).linear) } else { .air }