Files
voxelotl-engine/Sources/Voxelotl/Chunk.swift

136 lines
3.6 KiB
Swift
Raw Normal View History

2024-09-01 21:16:05 +10:00
public struct Chunk: Hashable {
2024-08-25 19:23:47 +10:00
public static let shift = 4 // 16
public static let size: Int = 1 << shift
public static let mask: Int = size - 1
2024-08-20 03:21:55 +10:00
2024-08-25 19:23:47 +10:00
public static let blockCount = size * size * size
private static let yStride = size
private static let zStride = size * size
2024-08-18 18:16:27 -07:00
2024-08-25 19:23:47 +10:00
public let origin: SIMD3<Int>
2024-08-18 18:16:27 -07:00
private var blocks: [Block]
init(position: SIMD3<Int>, blocks: [Block]) {
2024-08-20 03:21:55 +10:00
assert(blocks.count == Self.blockCount)
2024-08-25 19:23:47 +10:00
self.origin = position
2024-08-18 18:16:27 -07:00
self.blocks = blocks
}
init(position: SIMD3<Int>) {
2024-08-25 19:23:47 +10:00
self.origin = position
2024-08-18 18:16:27 -07:00
self.blocks = Array(
repeating: BlockType.air,
2024-08-20 03:21:55 +10:00
count: Self.blockCount
2024-08-18 18:16:27 -07:00
).map { type in Block(type) }
}
2024-08-20 03:21:55 +10:00
func getBlock(at position: SIMD3<Int>) -> Block {
2024-08-25 19:23:47 +10:00
getBlock(internal: position &- self.origin)
}
func getBlock(internal position: SIMD3<Int>) -> Block {
2024-08-20 03:21:55 +10:00
if position.x < 0 || position.y < 0 || position.z < 0 {
Block(.air)
2024-08-25 19:23:47 +10:00
} else if position.x >= Self.size || position.y >= Self.size || position.z >= Self.size {
2024-08-20 03:21:55 +10:00
Block(.air)
} else {
blocks[position.x + position.y * Self.yStride + position.z * Self.zStride]
}
2024-08-18 18:16:27 -07:00
}
2024-08-25 19:23:47 +10:00
2024-08-20 03:21:55 +10:00
mutating func setBlock(at position: SIMD3<Int>, type: BlockType) {
2024-08-25 19:23:47 +10:00
setBlock(internal: position &- self.origin, type: type)
}
mutating func setBlock(internal position: SIMD3<Int>, type: BlockType) {
2024-08-20 03:21:55 +10:00
if position.x < 0 || position.y < 0 || position.z < 0 {
2024-08-18 18:37:32 -07:00
return
}
2024-08-25 19:23:47 +10:00
if position.x >= Self.size || position.y >= Self.size || position.z >= Self.size {
2024-08-18 18:37:32 -07:00
return
}
2024-08-20 03:21:55 +10:00
blocks[position.x + position.y * Self.yStride + position.z * Self.zStride].type = type
2024-08-18 18:16:27 -07:00
}
2024-08-25 19:23:47 +10:00
2024-08-23 16:55:59 +10:00
mutating func fill(allBy calculation: (_ position: SIMD3<Int>) -> BlockType) {
2024-08-25 19:23:47 +10:00
for i in 0..<Self.blockCount {
let x = i & Self.mask
let y = (i &>> Self.shift) & Self.mask
let z = (i &>> (Self.shift + Self.shift)) & Self.mask
blocks[i].type = calculation(self.origin &+ SIMD3(x, y, z))
2024-08-20 03:21:55 +10:00
}
}
2024-09-01 21:16:05 +10:00
public func forEach(_ body: @escaping (Block, SIMD3<Int>) throws -> Void) rethrows {
for i in 0..<Self.blockCount {
2024-09-01 23:34:32 +10:00
try body(blocks[i], SIMD3(
2024-09-01 21:16:05 +10:00
x: i & Self.mask,
y: (i &>> Self.shift) & Self.mask,
z: (i &>> (Self.shift + Self.shift)) & Self.mask))
}
}
2024-08-20 03:21:55 +10:00
public func map<T>(block transform: (Block, SIMD3<Int>) throws -> T) rethrows -> [T] {
assert(self.blocks.count == Self.blockCount)
var out = [T]()
out.reserveCapacity(Self.blockCount)
var position = SIMD3<Int>()
for i in self.blocks.indices {
2024-08-25 19:23:47 +10:00
out.append(try transform(blocks[i], self.origin &+ position))
2024-08-20 03:21:55 +10:00
position.x += 1
2024-08-25 19:23:47 +10:00
if position.x == Self.size {
2024-08-20 03:21:55 +10:00
position.x = 0
position.y += 1
2024-08-25 19:23:47 +10:00
if position.y == Self.size {
2024-08-20 03:21:55 +10:00
position.y = 0
position.z += 1
2024-08-18 18:16:27 -07:00
}
}
}
2024-08-20 03:21:55 +10:00
return out
}
public func compactMap<T>(block transform: (Block, SIMD3<Int>) throws -> T?) rethrows -> [T] {
assert(self.blocks.count == Self.blockCount)
var out = [T]()
out.reserveCapacity(Self.blockCount >> 1)
var position = SIMD3<Int>()
for i in self.blocks.indices {
2024-08-25 19:23:47 +10:00
if let element = try transform(blocks[i], self.origin &+ position) {
2024-08-20 03:21:55 +10:00
out.append(element)
}
position.x += 1
2024-08-25 19:23:47 +10:00
if position.x == Self.size {
2024-08-20 03:21:55 +10:00
position.x = 0
position.y += 1
2024-08-25 19:23:47 +10:00
if position.y == Self.size {
2024-08-20 03:21:55 +10:00
position.y = 0
position.z += 1
}
}
}
return out
2024-08-18 18:16:27 -07:00
}
}
2024-09-01 21:16:05 +10:00
public enum BlockType: Hashable {
2024-08-18 18:16:27 -07:00
case air
case solid(_ color: Color<Float>)
2024-08-18 18:16:27 -07:00
}
2024-09-01 21:16:05 +10:00
public struct Block: Hashable {
2024-08-18 18:16:27 -07:00
public var type: BlockType
2024-08-20 03:21:55 +10:00
2024-08-18 18:16:27 -07:00
public init(_ type: BlockType) {
self.type = type
}
}