Eliminate opposing walls
This commit is contained in:
61
src/Game.zig
61
src/Game.zig
@@ -15,7 +15,7 @@ const Engine = @import("engine/Engine.zig");
|
||||
const GenericBuffer = @import("engine/GenericBuffer.zig").GenericBuffer;
|
||||
const StagingBuffer = @import("engine/StagingBuffer.zig");
|
||||
const Swapchain = @import("engine/Swapchain.zig");
|
||||
const Iterator3 = math.Iterator3;
|
||||
const Interator3 = math.Interator3;
|
||||
const Matrix4x4 = math.Matrix4x4;
|
||||
const Quaternion = math.Quaternion;
|
||||
const Vector2 = math.Vector2;
|
||||
@@ -117,7 +117,7 @@ index_buffer: IndexBuffer,
|
||||
|
||||
global_uniforms: GlobalUniformsBuffer,
|
||||
global_uniforms_staging_buffer: StagingBuffer,
|
||||
global_uniforms_transfer_command_buffer: CommandBuffer(.graphics, .persistent),
|
||||
global_uniforms_transfer_command_buffer: CommandBuffer(.transfer, .persistent),
|
||||
global_uniforms_transfer_semaphores: []vk.Semaphore,
|
||||
point_lights: PointLightBuffer,
|
||||
directional_lights: DirectionalLightBuffer,
|
||||
@@ -126,7 +126,7 @@ sampler: vk.Sampler,
|
||||
blocks: Blocks,
|
||||
materials: Materials,
|
||||
textures: Textures,
|
||||
chunks: std.ArrayList(Chunk),
|
||||
chunks: std.AutoHashMapUnmanaged([3]i16, Chunk),
|
||||
|
||||
camera_position: Vector3 = .init(0, 0, 1.62),
|
||||
camera_pitch: f32 = 0,
|
||||
@@ -142,7 +142,7 @@ input_down: bool = false,
|
||||
const max_textures = 1024;
|
||||
const max_point_lights = 1024;
|
||||
const max_directional_lights = 4;
|
||||
const max_objects = 1024;
|
||||
const chunk_descriptor_pool = 512;
|
||||
|
||||
const camera_near_plane = 0.1;
|
||||
const camera_vertical_fov_deg = 80.0;
|
||||
@@ -318,7 +318,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
});
|
||||
errdefer global_uniforms_staging_buffer.deinit(engine);
|
||||
|
||||
var global_uniforms_transfer_command_buffer: CommandBuffer(.graphics, .persistent) = try .init(engine);
|
||||
var global_uniforms_transfer_command_buffer: CommandBuffer(.transfer, .persistent) = try .init(engine);
|
||||
errdefer global_uniforms_transfer_command_buffer.deinit(engine);
|
||||
|
||||
try global_uniforms_transfer_command_buffer.beginCommandBuffer(.{});
|
||||
@@ -491,7 +491,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
engine.setObjectName(pipeline, "P", .{});
|
||||
|
||||
const descriptor_pool = try engine.createDescriptorPool(.{
|
||||
.max_sets = 1 + 256,
|
||||
.max_sets = 1 + chunk_descriptor_pool,
|
||||
.pool_sizes = &.{
|
||||
.{
|
||||
.type = .sampler,
|
||||
@@ -507,7 +507,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
},
|
||||
.{
|
||||
.type = .storage_buffer,
|
||||
.descriptor_count = 3 + 256,
|
||||
.descriptor_count = 3 + chunk_descriptor_pool,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -603,33 +603,51 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
},
|
||||
});
|
||||
|
||||
var chunks: std.ArrayList(Chunk) = .empty;
|
||||
var chunks: std.AutoHashMapUnmanaged([3]i16, Chunk) = .empty;
|
||||
errdefer {
|
||||
for (chunks.items) |*chunk| {
|
||||
var it = chunks.valueIterator();
|
||||
while (it.next()) |chunk| {
|
||||
chunk.deinit(engine, descriptor_pool);
|
||||
}
|
||||
chunks.deinit(allocator);
|
||||
}
|
||||
|
||||
var it: Iterator3 = .init(.init(-64, -64, 0), .init(64, 64, 0), .init(16, 16, 16));
|
||||
while (it.next()) |origin| {
|
||||
var it = Interator3(i16).init(-10, -10, 0, 9, 9, 0);
|
||||
while (it.next()) |chunk_coords| {
|
||||
const origin = Vector3.init(
|
||||
@floatFromInt(chunk_coords[0]),
|
||||
@floatFromInt(chunk_coords[1]),
|
||||
@floatFromInt(chunk_coords[2]),
|
||||
).mulScalar(16);
|
||||
|
||||
try chunks.ensureUnusedCapacity(allocator, 1);
|
||||
chunks.appendAssumeCapacity(try Chunk.init(engine, .{
|
||||
chunks.putAssumeCapacityNoClobber(chunk_coords, try Chunk.init(engine, .{
|
||||
.origin = origin,
|
||||
.descriptor_pool = descriptor_pool,
|
||||
.per_batch_descriptor_set_layout = per_batch_descriptor_set_layout,
|
||||
}));
|
||||
const chunk = chunks.getPtr(chunk_coords).?;
|
||||
|
||||
const chunk = &chunks.items[chunks.items.len - 1];
|
||||
|
||||
var it2 = Iterator3.init(.init(0, 0, 0), .init(1, 1, 0), .{ .vector = @splat(1.0 / 16.0) });
|
||||
while (it2.next()) |fpos| {
|
||||
const x, const y, const z = fpos.asArrayNorm(u4);
|
||||
var it2 = Interator3(usize).init(0, 0, 0, 15, 15, 0);
|
||||
while (it2.next()) |pos| {
|
||||
const x, const y, const z = pos;
|
||||
const block: Blocks.Id = @enumFromInt(engine.random.intRangeLessThan(u12, 1, @intCast(blocks.blocks.items.len)));
|
||||
chunk.blocks[z][y][x] = block;
|
||||
}
|
||||
}
|
||||
|
||||
try chunk.refresh(engine, &blocks, allocator);
|
||||
var chunk_it = chunks.iterator();
|
||||
while (chunk_it.next()) |entry| {
|
||||
const x, const y, const z = entry.key_ptr.*;
|
||||
const chunk = entry.value_ptr;
|
||||
try chunk.refresh(engine, &blocks, .{
|
||||
.positive_x = chunks.getPtr(.{ x + 1, y, z }),
|
||||
.negative_x = chunks.getPtr(.{ x - 1, y, z }),
|
||||
.positive_y = chunks.getPtr(.{ x, y + 1, z }),
|
||||
.negative_y = chunks.getPtr(.{ x, y - 1, z }),
|
||||
.positive_z = chunks.getPtr(.{ x, y, z + 1 }),
|
||||
.negative_z = chunks.getPtr(.{ x, y, z - 1 }),
|
||||
}, allocator);
|
||||
}
|
||||
|
||||
const point_lights_data: []const PointLight = &.{};
|
||||
@@ -683,7 +701,9 @@ pub fn deinit(self: *Game) void {
|
||||
|
||||
self.vertex_buffer.deinit(self.engine);
|
||||
self.index_buffer.deinit(self.engine);
|
||||
for (self.chunks.items) |*chunk| {
|
||||
|
||||
var it = self.chunks.valueIterator();
|
||||
while (it.next()) |chunk| {
|
||||
chunk.deinit(self.engine, self.descriptor_pool);
|
||||
}
|
||||
self.chunks.deinit(self.allocator);
|
||||
@@ -916,7 +936,8 @@ fn render(self: *Game) !void {
|
||||
command_buffer.bindIndexBuffer(self.index_buffer.buffer, 0, .uint16);
|
||||
command_buffer.bindDescriptorSet(.graphics, self.pipeline_layout, 0, self.global_descriptor_set, null);
|
||||
|
||||
for (self.chunks.items) |chunk| {
|
||||
var it = self.chunks.valueIterator();
|
||||
while (it.next()) |chunk| {
|
||||
chunk.draw(self.pipeline_layout, command_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ const CommandBuffer = @import("../engine/CommandBuffer.zig").CommandBuffer;
|
||||
const Engine = @import("../engine/Engine.zig");
|
||||
const Game = @import("../Game.zig");
|
||||
const GenericBuffer = @import("../engine/GenericBuffer.zig").GenericBuffer;
|
||||
const Materials = @import("Materials.zig");
|
||||
const Orientation = @import("../voxel.zig").Orientation;
|
||||
|
||||
const Matrix4x4 = math.Matrix4x4;
|
||||
const ObjectUniformsBuffer = GenericBuffer(void, Game.ObjectUniforms);
|
||||
@@ -20,11 +22,15 @@ pub const chunk_size = 16;
|
||||
const initial_capacity = 256;
|
||||
var next_chunk_id: std.atomic.Value(u64) = .init(0);
|
||||
|
||||
/// To get the block at coordinates (x, y, z) relative to the chunk, read the
|
||||
/// value at `blocks[z][y][x]`.
|
||||
blocks: [chunk_size][chunk_size][chunk_size]Blocks.Id,
|
||||
origin: Vector3,
|
||||
descriptor_set: vk.DescriptorSet,
|
||||
object_buffer: ObjectUniformsBuffer,
|
||||
object_count: u32,
|
||||
|
||||
/// For debug purposes, a unique "name" per chunk instance.
|
||||
chunk_id: u64,
|
||||
|
||||
pub const InitInfo = struct {
|
||||
@@ -33,6 +39,15 @@ pub const InitInfo = struct {
|
||||
per_batch_descriptor_set_layout: vk.DescriptorSetLayout,
|
||||
};
|
||||
|
||||
pub const Neighbors = struct {
|
||||
positive_x: ?*const Chunk,
|
||||
negative_x: ?*const Chunk,
|
||||
positive_y: ?*const Chunk,
|
||||
negative_y: ?*const Chunk,
|
||||
positive_z: ?*const Chunk,
|
||||
negative_z: ?*const Chunk,
|
||||
};
|
||||
|
||||
pub fn init(engine: *Engine, init_info: InitInfo) !Chunk {
|
||||
const descriptor_set = try engine.allocateDescriptorSet(.{
|
||||
.descriptor_pool = init_info.descriptor_pool,
|
||||
@@ -89,23 +104,97 @@ pub fn deinit(self: *Chunk, engine: *Engine, descriptor_pool: vk.DescriptorPool)
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub fn refresh(self: *Chunk, engine: *Engine, blocks: *const Blocks, temp_allocator: std.mem.Allocator) !void {
|
||||
var object_count: u32 = 0;
|
||||
pub fn refresh(self: *Chunk, engine: *Engine, blocks: *const Blocks, neighbors: Neighbors, temp_allocator: std.mem.Allocator) !void {
|
||||
var uniforms: std.ArrayList(Game.ObjectUniforms) = try .initCapacity(temp_allocator, initial_capacity);
|
||||
defer uniforms.deinit(temp_allocator);
|
||||
|
||||
for (self.blocks) |plane| {
|
||||
for (plane) |row| {
|
||||
for (row) |id| {
|
||||
for (self.blocks, 0..) |plane, iz| {
|
||||
const fz: f32 = @floatFromInt(iz);
|
||||
for (plane, 0..) |row, iy| {
|
||||
const fy: f32 = @floatFromInt(iy);
|
||||
for (row, 0..) |id, ix| {
|
||||
const fx: f32 = @floatFromInt(ix);
|
||||
const block = blocks.getBlock(id).?;
|
||||
object_count += @intFromBool(block.positive_x != .empty);
|
||||
object_count += @intFromBool(block.negative_x != .empty);
|
||||
object_count += @intFromBool(block.positive_y != .empty);
|
||||
object_count += @intFromBool(block.negative_y != .empty);
|
||||
object_count += @intFromBool(block.positive_z != .empty);
|
||||
object_count += @intFromBool(block.negative_z != .empty);
|
||||
|
||||
const center = Vector3.add(self.origin, .init(fx, fy, fz));
|
||||
const cx, const cy, const cz = center.asArray();
|
||||
|
||||
if (block.positive_x != .empty and self.getOpposite(.positive_x, ix, iy, iz, blocks, neighbors) == .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
1, 0, 0, 0,
|
||||
cx + 0.5, cy, cz, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
try uniforms.append(temp_allocator, .init(matrix, matrix, block.positive_x));
|
||||
}
|
||||
|
||||
if (block.negative_x != .empty and self.getOpposite(.negative_x, ix, iy, iz, blocks, neighbors) == .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
0, -1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
-1, 0, 0, 0,
|
||||
cx - 0.5, cy, cz, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
try uniforms.append(temp_allocator, .init(matrix, matrix, block.negative_x));
|
||||
}
|
||||
|
||||
if (block.positive_y != .empty and self.getOpposite(.positive_y, ix, iy, iz, blocks, neighbors) == .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
-1, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 1, 0, 0,
|
||||
cx, cy + 0.5, cz, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
try uniforms.append(temp_allocator, .init(matrix, matrix, block.positive_y));
|
||||
}
|
||||
|
||||
if (block.negative_y != .empty and self.getOpposite(.negative_y, ix, iy, iz, blocks, neighbors) == .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
1, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, -1, 0, 0,
|
||||
cx, cy - 0.5, cz, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
try uniforms.append(temp_allocator, .init(matrix, matrix, block.negative_y));
|
||||
}
|
||||
|
||||
if (block.positive_z != .empty and self.getOpposite(.positive_z, ix, iy, iz, blocks, neighbors) == .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
cx, cy, cz + 0.5, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
try uniforms.append(temp_allocator, .init(matrix, matrix, block.positive_z));
|
||||
}
|
||||
|
||||
if (block.negative_z != .empty and self.getOpposite(.negative_z, ix, iy, iz, blocks, neighbors) == .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
1, 0, 0, 0,
|
||||
0, -1, 0, 0,
|
||||
0, 0, -1, 0,
|
||||
cx, cy, cz - 0.5, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
try uniforms.append(temp_allocator, .init(matrix, matrix, block.negative_z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const object_count: u32 = @intCast(uniforms.items.len);
|
||||
if (self.object_buffer.array_capacity < object_count) {
|
||||
const desired_capacity = std.math.ceilPowerOfTwoAssert(u32, object_count);
|
||||
const new_object_buffer: ObjectUniformsBuffer = try .init(engine, .{
|
||||
@@ -140,105 +229,7 @@ pub fn refresh(self: *Chunk, engine: *Engine, blocks: *const Blocks, temp_alloca
|
||||
engine.setObjectName(new_object_buffer.device_memory, "DM Chunk[{d}]", .{self.chunk_id});
|
||||
}
|
||||
|
||||
const uniforms = try temp_allocator.alloc(Game.ObjectUniforms, object_count);
|
||||
var object_i: usize = 0;
|
||||
defer temp_allocator.free(uniforms);
|
||||
|
||||
for (self.blocks, 0..) |plane, iz| {
|
||||
const fz: f32 = @floatFromInt(iz);
|
||||
for (plane, 0..) |row, iy| {
|
||||
const fy: f32 = @floatFromInt(iy);
|
||||
for (row, 0..) |id, ix| {
|
||||
const fx: f32 = @floatFromInt(ix);
|
||||
const block = blocks.getBlock(id).?;
|
||||
|
||||
const center = Vector3.add(self.origin, .init(fx, fy, fz));
|
||||
const cx, const cy, const cz = center.asArray();
|
||||
|
||||
if (block.positive_x != .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
1, 0, 0, 0,
|
||||
cx + 0.5, cy, cz, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
uniforms[object_i] = .init(matrix, matrix, block.positive_x);
|
||||
object_i += 1;
|
||||
}
|
||||
|
||||
if (block.negative_x != .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
0, -1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
-1, 0, 0, 0,
|
||||
cx - 0.5, cy, cz, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
uniforms[object_i] = .init(matrix, matrix, block.negative_x);
|
||||
object_i += 1;
|
||||
}
|
||||
|
||||
if (block.positive_y != .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
-1, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 1, 0, 0,
|
||||
cx, cy + 0.5, cz, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
uniforms[object_i] = .init(matrix, matrix, block.positive_y);
|
||||
object_i += 1;
|
||||
}
|
||||
|
||||
if (block.negative_y != .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
1, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, -1, 0, 0,
|
||||
cx, cy - 0.5, cz, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
uniforms[object_i] = .init(matrix, matrix, block.negative_y);
|
||||
object_i += 1;
|
||||
}
|
||||
|
||||
if (block.positive_z != .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
cx, cy, cz + 0.5, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
uniforms[object_i] = .init(matrix, matrix, block.positive_z);
|
||||
object_i += 1;
|
||||
}
|
||||
|
||||
if (block.negative_z != .empty) {
|
||||
// zig fmt: off
|
||||
const matrix: Matrix4x4 = .init(
|
||||
1, 0, 0, 0,
|
||||
0, -1, 0, 0,
|
||||
0, 0, -1, 0,
|
||||
cx, cy, cz - 0.5, 1,
|
||||
);
|
||||
// zig fmt: on
|
||||
uniforms[object_i] = .init(matrix, matrix, block.negative_z);
|
||||
object_i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std.debug.assert(object_i == uniforms.len);
|
||||
|
||||
try self.object_buffer.write(engine, .{ .elements = uniforms });
|
||||
try self.object_buffer.write(engine, .{ .elements = uniforms.items });
|
||||
self.object_count = object_count;
|
||||
}
|
||||
|
||||
@@ -246,3 +237,44 @@ pub fn draw(self: *const Chunk, layout: vk.PipelineLayout, command_buffer: Comma
|
||||
command_buffer.bindDescriptorSets(.graphics, layout, 1, &.{self.descriptor_set}, &.{});
|
||||
command_buffer.drawIndexed(.{ .index_count = 6, .instance_count = self.object_count });
|
||||
}
|
||||
|
||||
fn getOpposite(self: *const Chunk, comptime side: Orientation, x: usize, y: usize, z: usize, blocks: *const Blocks, neighbors: Neighbors) Materials.Id {
|
||||
return switch (side) {
|
||||
.positive_x => if (x + 1 < chunk_size)
|
||||
blocks.getBlock(self.blocks[z][y][x + 1]).?.negative_x
|
||||
else if (neighbors.positive_x) |neighbor|
|
||||
blocks.getBlock(neighbor.blocks[z][y][0]).?.negative_x
|
||||
else
|
||||
.empty,
|
||||
.negative_x => if (x > 0)
|
||||
blocks.getBlock(self.blocks[z][y][x - 1]).?.positive_x
|
||||
else if (neighbors.negative_x) |neighbor|
|
||||
blocks.getBlock(neighbor.blocks[z][y][chunk_size - 1]).?.positive_x
|
||||
else
|
||||
.empty,
|
||||
.positive_y => if (y + 1 < chunk_size)
|
||||
blocks.getBlock(self.blocks[z][y + 1][x]).?.negative_y
|
||||
else if (neighbors.positive_y) |neighbor|
|
||||
blocks.getBlock(neighbor.blocks[z][0][x]).?.negative_y
|
||||
else
|
||||
.empty,
|
||||
.negative_y => if (y > 0)
|
||||
blocks.getBlock(self.blocks[z][y - 1][x]).?.positive_y
|
||||
else if (neighbors.negative_y) |neighbor|
|
||||
blocks.getBlock(neighbor.blocks[z][chunk_size - 1][x]).?.positive_y
|
||||
else
|
||||
.empty,
|
||||
.positive_z => if (z + 1 < chunk_size)
|
||||
blocks.getBlock(self.blocks[z + 1][y][x]).?.negative_z
|
||||
else if (neighbors.positive_z) |neighbor|
|
||||
blocks.getBlock(neighbor.blocks[0][y][x]).?.negative_z
|
||||
else
|
||||
.empty,
|
||||
.negative_z => if (z > 0)
|
||||
blocks.getBlock(self.blocks[z - 1][y][x]).?.positive_z
|
||||
else if (neighbors.negative_z) |neighbor|
|
||||
blocks.getBlock(neighbor.blocks[chunk_size - 1][y][x]).?.positive_z
|
||||
else
|
||||
.empty,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub const Interator3 = @import("math/Interator3.zig").Interator3;
|
||||
pub const Iterator3 = @import("math/Iterator3.zig");
|
||||
pub const Matrix4x4 = @import("math/Matrix4x4.zig").Matrix4x4;
|
||||
pub const Quaternion = @import("math/Quaternion.zig").Quaternion;
|
||||
|
||||
42
src/math/Interator3.zig
Normal file
42
src/math/Interator3.zig
Normal file
@@ -0,0 +1,42 @@
|
||||
pub fn Interator3(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
const Vector = @Vector(3, T);
|
||||
|
||||
min: Vector,
|
||||
max: Vector,
|
||||
current: ?Vector,
|
||||
|
||||
pub fn init(min_x: T, min_y: T, min_z: T, max_x: T, max_y: T, max_z: T) Self {
|
||||
const min: Vector = .{ min_x, min_y, min_z };
|
||||
const max: Vector = .{ max_x, max_y, max_z };
|
||||
return .{
|
||||
.min = min,
|
||||
.max = max,
|
||||
.current = min,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn next(self: *Self) ?[3]T {
|
||||
const current = self.current orelse return null;
|
||||
var next_current = current;
|
||||
|
||||
next_current[0] = next_current[0] + 1;
|
||||
if (next_current[0] > self.max[0]) {
|
||||
next_current[0] = self.min[0];
|
||||
next_current[1] = next_current[1] + 1;
|
||||
if (next_current[1] > self.max[1]) {
|
||||
next_current[1] = self.min[1];
|
||||
next_current[2] = next_current[2] + 1;
|
||||
if (next_current[2] > self.max[2]) {
|
||||
self.current = null;
|
||||
return current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.current = next_current;
|
||||
return current;
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user