refactor: add comments and rename variables in chunk.zig
This commit is contained in:
parent
ed1e0ecb6b
commit
371c3545dd
1 changed files with 48 additions and 43 deletions
|
|
@ -28,6 +28,7 @@ const RawQuad = struct {
|
||||||
bottom_left_obscured: bool,
|
bottom_left_obscured: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Quad shader metadata. Has to be 128 bytes in size.
|
||||||
const Metadata1 = packed struct {
|
const Metadata1 = packed struct {
|
||||||
ambient_occlusion_1: u32,
|
ambient_occlusion_1: u32,
|
||||||
ambient_occlusion_2: u32,
|
ambient_occlusion_2: u32,
|
||||||
|
|
@ -63,23 +64,23 @@ pub const Chunk = struct {
|
||||||
self.a7r.free(self.tiles);
|
self.a7r.free(self.tiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch the tile at (x, y, z), but with potential side effects. If you imagine tiles to be a 3-dimensional array, this would be tiles[x][y][z].
|
||||||
pub fn getTile(self: Chunk, x: u5, y: u5, z: u5) u32 {
|
pub fn getTile(self: Chunk, x: u5, y: u5, z: u5) u32 {
|
||||||
// Fetch the tile at (x, y, z), but with potential side effects. If you imagine tiles to be a 3-dimensional array, this would be tiles[x][y][z].
|
|
||||||
return self.tiles[@as(u15, x) << 10 | @as(u15, y) << 5 | @as(u15, z)];
|
return self.tiles[@as(u15, x) << 10 | @as(u15, y) << 5 | @as(u15, z)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the tile at (x, y, z). If you imagine tiles to be a 3-dimensional array, this would be tiles[x][y][z] = tile.
|
||||||
pub fn setTile(self: Chunk, x: u5, y: u5, z: u5, tile: u32) void {
|
pub fn setTile(self: Chunk, x: u5, y: u5, z: u5, tile: u32) void {
|
||||||
// Set the tile at (x, y, z). If you imagine tiles to be a 3-dimensional array, this would be tiles[x][y][z] = tile.
|
|
||||||
self.tiles[@as(u15, x) << 10 | @as(u15, y) << 5 | @as(u15, z)] = tile;
|
self.tiles[@as(u15, x) << 10 | @as(u15, y) << 5 | @as(u15, z)] = tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch the tile at (x, y, z) without changin anything. If you imagine tiles to be a 3-dimensional array, this would be tiles[x][y][z].
|
||||||
fn getTileRaw(self: Chunk, x: u5, y: u5, z: u5) u32 {
|
fn getTileRaw(self: Chunk, x: u5, y: u5, z: u5) u32 {
|
||||||
// Fetch the tile at (x, y, z) without changin anything. If you imagine tiles to be a 3-dimensional array, this would be tiles[x][y][z].
|
|
||||||
return self.tiles[@as(u15, x) << 10 | @as(u15, y) << 5 | @as(u15, z)];
|
return self.tiles[@as(u15, x) << 10 | @as(u15, y) << 5 | @as(u15, z)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This cyclically permutes the x, y, z coordinates at compile time. Useful when iterating over x, y, and z axis.
|
||||||
inline fn getTileRawShifted(self: Chunk, x: u5, y: u5, z: u5, comptime d: comptime_int) u32 {
|
inline fn getTileRawShifted(self: Chunk, x: u5, y: u5, z: u5, comptime d: comptime_int) u32 {
|
||||||
// This cyclicaly permutes the x, y, z coordinates at compile time. Useful when iterating over x, y, and z axis.
|
|
||||||
if (d % 3 == 0) {
|
if (d % 3 == 0) {
|
||||||
return self.getTileRaw(x, y, z);
|
return self.getTileRaw(x, y, z);
|
||||||
} else if (d % 3 == 1) {
|
} else if (d % 3 == 1) {
|
||||||
|
|
@ -89,24 +90,25 @@ pub const Chunk = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pack_raw_quad(y: usize, y2: usize, z: usize, z2: usize, sign: comptime_int, d: comptime_int, surface: u32, xf: f32) RawQuad {
|
// Create a raw quad with specified parameters and surface, accounting for dimension and sign. Surface is the block ID.
|
||||||
const ymin: f32 = @as(f32, @floatFromInt(y)) - 0.5;
|
fn pack_raw_quad(x: f32, y_start: usize, y_end: usize, z_start: usize, z_end: usize, sign: comptime_int, d: comptime_int, surface: u32) RawQuad {
|
||||||
const ymax: f32 = @as(f32, @floatFromInt(y2)) + 0.5;
|
const ymin: f32 = @as(f32, @floatFromInt(y_start)) - 0.5;
|
||||||
const zmin: f32 = @as(f32, @floatFromInt(z)) - 0.5;
|
const ymax: f32 = @as(f32, @floatFromInt(y_end)) - 0.5;
|
||||||
const zmax: f32 = @as(f32, @floatFromInt(z2)) + 0.5;
|
const zmin: f32 = @as(f32, @floatFromInt(z_start)) - 0.5;
|
||||||
|
const zmax: f32 = @as(f32, @floatFromInt(z_end)) - 0.5;
|
||||||
const yleft: f32 = if (sign == 1) ymin else ymax;
|
const yleft: f32 = if (sign == 1) ymin else ymax;
|
||||||
const yright: f32 = if (sign == 1) ymax else ymin;
|
const yright: f32 = if (sign == 1) ymax else ymin;
|
||||||
const zleft: f32 = if (sign == 1) zmin else zmax;
|
const zleft: f32 = if (sign == 1) zmin else zmax;
|
||||||
const zright: f32 = if (sign == 1) zmax else zmin;
|
const zright: f32 = if (sign == 1) zmax else zmin;
|
||||||
var raw_quad: RawQuad = undefined;
|
var raw_quad: RawQuad = undefined;
|
||||||
switch (d) {
|
switch (d) {
|
||||||
0 => {
|
0 => { // X direction
|
||||||
raw_quad = .{
|
raw_quad = .{
|
||||||
.tile = surface,
|
.tile = surface,
|
||||||
.top_left = v3.new(xf + 0.5 * sign, ymax, zright),
|
.top_left = v3.new(x + 0.5 * sign, ymax, zright),
|
||||||
.top_right = v3.new(xf + 0.5 * sign, ymax, zleft),
|
.top_right = v3.new(x + 0.5 * sign, ymax, zleft),
|
||||||
.bottom_left = v3.new(xf + 0.5 * sign, ymin, zright),
|
.bottom_left = v3.new(x + 0.5 * sign, ymin, zright),
|
||||||
.bottom_right = v3.new(xf + 0.5 * sign, ymin, zleft),
|
.bottom_right = v3.new(x + 0.5 * sign, ymin, zleft),
|
||||||
.normal = v3.new(sign, 0, 0),
|
.normal = v3.new(sign, 0, 0),
|
||||||
.width = zmax - zmin,
|
.width = zmax - zmin,
|
||||||
.height = ymax - ymin,
|
.height = ymax - ymin,
|
||||||
|
|
@ -121,13 +123,13 @@ pub const Chunk = struct {
|
||||||
.bottom_left_obscured = false,
|
.bottom_left_obscured = false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
1 => {
|
1 => { // Y direction
|
||||||
raw_quad = .{
|
raw_quad = .{
|
||||||
.tile = surface,
|
.tile = surface,
|
||||||
.bottom_left = v3.new(yleft, zmin, xf + 0.5 * sign),
|
.bottom_left = v3.new(yleft, zmin, x + 0.5 * sign),
|
||||||
.top_left = v3.new(yleft, zmax, xf + 0.5 * sign),
|
.top_left = v3.new(yleft, zmax, x + 0.5 * sign),
|
||||||
.bottom_right = v3.new(yright, zmin, xf + 0.5 * sign),
|
.bottom_right = v3.new(yright, zmin, x + 0.5 * sign),
|
||||||
.top_right = v3.new(yright, zmax, xf + 0.5 * sign),
|
.top_right = v3.new(yright, zmax, x + 0.5 * sign),
|
||||||
.normal = v3.new(0, 0, sign),
|
.normal = v3.new(0, 0, sign),
|
||||||
.height = zmax - zmin,
|
.height = zmax - zmin,
|
||||||
.width = ymax - ymin,
|
.width = ymax - ymin,
|
||||||
|
|
@ -142,13 +144,13 @@ pub const Chunk = struct {
|
||||||
.bottom_left_obscured = false,
|
.bottom_left_obscured = false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
2 => {
|
2 => { // Z direction
|
||||||
raw_quad = .{
|
raw_quad = .{
|
||||||
.tile = surface,
|
.tile = surface,
|
||||||
.top_left = v3.new(zleft, xf + 0.5 * sign, ymin),
|
.top_left = v3.new(zleft, x + 0.5 * sign, ymin),
|
||||||
.top_right = v3.new(zright, xf + 0.5 * sign, ymin),
|
.top_right = v3.new(zright, x + 0.5 * sign, ymin),
|
||||||
.bottom_left = v3.new(zleft, xf + 0.5 * sign, ymax),
|
.bottom_left = v3.new(zleft, x + 0.5 * sign, ymax),
|
||||||
.bottom_right = v3.new(zright, xf + 0.5 * sign, ymax),
|
.bottom_right = v3.new(zright, x + 0.5 * sign, ymax),
|
||||||
.normal = v3.new(0, sign, 0),
|
.normal = v3.new(0, sign, 0),
|
||||||
.width = zmax - zmin,
|
.width = zmax - zmin,
|
||||||
.height = ymax - ymin,
|
.height = ymax - ymin,
|
||||||
|
|
@ -168,44 +170,47 @@ pub const Chunk = struct {
|
||||||
return raw_quad;
|
return raw_quad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create mesh of a chunk. tile_rows and tile_columns are the dimensions of the tiles.png file, in terms of individual tile textures.
|
||||||
pub fn createMesh(chunk: Chunk, tile_rows: u32, tile_columns: u32) !raylib.Mesh {
|
pub fn createMesh(chunk: Chunk, tile_rows: u32, tile_columns: u32) !raylib.Mesh {
|
||||||
var raw_quads = try std.ArrayList(RawQuad).initCapacity(chunk.a7r, 4096);
|
var raw_quads = try std.ArrayList(RawQuad).initCapacity(chunk.a7r, 4096);
|
||||||
defer raw_quads.deinit();
|
defer raw_quads.deinit();
|
||||||
|
|
||||||
// Begin scanning the chunk for block surfaces to make raw quads.
|
// Begin scanning the chunk for tile surfaces to make raw quads.
|
||||||
inline for (0..3) |d| { // For each of the 3 dimensions,
|
inline for (0..3) |d| { // Iterate over the 3 dimensions, X, Y and Z.
|
||||||
for (0..32) |raw_x| {
|
for (0..32) |raw_x| {
|
||||||
const x: u5 = @intCast(raw_x);
|
const x: u5 = @intCast(raw_x);
|
||||||
|
// Create surface arrays for the +x side of the layer and the -x side.
|
||||||
var positive_tile_surfaces: [32][32]u32 = .{.{0} ** 32} ** 32;
|
var positive_tile_surfaces: [32][32]u32 = .{.{0} ** 32} ** 32;
|
||||||
var negative_tile_surfaces: [32][32]u32 = .{.{0} ** 32} ** 32;
|
var negative_tile_surfaces: [32][32]u32 = .{.{0} ** 32} ** 32;
|
||||||
for (0..32) |raw_y| for (0..32) |raw_z| {
|
for (0..32) |raw_y| for (0..32) |raw_z| {
|
||||||
const y: u5 = @intCast(raw_y);
|
const y: u5 = @intCast(raw_y);
|
||||||
const z: u5 = @intCast(raw_z);
|
const z: u5 = @intCast(raw_z);
|
||||||
const tile: u32 = chunk.getTileRawShifted(x, y, z, d);
|
const tile: u32 = chunk.getTileRawShifted(x, y, z, d);
|
||||||
if (tile == 0) continue;
|
if (tile == 0) continue; // If air, there is no surface.
|
||||||
|
// If either at the edge of the chunk or the tile is exposed, create a tile surface.
|
||||||
if (x == 31 or chunk.getTileRawShifted(x + 1, y, z, d) == 0) positive_tile_surfaces[y][z] = tile;
|
if (x == 31 or chunk.getTileRawShifted(x + 1, y, z, d) == 0) positive_tile_surfaces[y][z] = tile;
|
||||||
if (x == 0 or chunk.getTileRawShifted(x - 1, y, z, d) == 0) negative_tile_surfaces[y][z] = tile;
|
if (x == 0 or chunk.getTileRawShifted(x - 1, y, z, d) == 0) negative_tile_surfaces[y][z] = tile;
|
||||||
};
|
};
|
||||||
const xf: f32 = @floatFromInt(raw_x);
|
|
||||||
inline for (.{ -1, 1 }) |sign| {
|
inline for (.{ -1, 1 }) |sign| {
|
||||||
var tile_surfaces = if (sign == 1) positive_tile_surfaces else negative_tile_surfaces;
|
var tile_surfaces = if (sign == 1) positive_tile_surfaces else negative_tile_surfaces;
|
||||||
for (0..32) |y| for (0..32) |z| {
|
for (0..32) |y_start| for (0..32) |z_start| {
|
||||||
const surface = tile_surfaces[y][z];
|
const surface = tile_surfaces[y_start][z_start]; // Starting surface tile type.
|
||||||
if (surface == 0) continue;
|
if (surface == 0) continue; // No surface if air.
|
||||||
var y2 = y + 1;
|
tile_surfaces[y_start][z_start] = 0; // Replace this surface with air, since the corresponding quad will be created.
|
||||||
var z2 = z + 1;
|
// The end coordinates of the quad. The quad is therefore covers rectangle from start coordinates (inclusive) to end coordinates (exclusive).
|
||||||
while (y2 <= 31 and tile_surfaces[y2][z] == surface) : (y2 += 1) {
|
var y_end = y_start + 1;
|
||||||
tile_surfaces[y2][z] = 0;
|
var z_end = z_start + 1;
|
||||||
|
// Greedy meshing: Extend the quad in the +y direction, until we hit a tile of a different type or the end of the chunk.
|
||||||
|
while (y_end <= 31 and tile_surfaces[y_end][z_start] == surface) : (y_end += 1) {
|
||||||
|
tile_surfaces[y_end][z_start] = 0;
|
||||||
}
|
}
|
||||||
zloop: while (z2 <= 31) : (z2 += 1) {
|
// Greedy meshing: Extend the quad in the +z direction, until the next line does not consist of tiles of correct type.
|
||||||
for (y..y2) |ytmp| if (tile_surfaces[ytmp][z2] != surface) break :zloop;
|
zloop: while (z_end <= 31) : (z_end += 1) {
|
||||||
for (y..y2) |ytmp| tile_surfaces[ytmp][z2] = 0;
|
for (y_start..y_end) |y| if (tile_surfaces[y][z_end] != surface) break :zloop; // Stop extending if we hit a tile of incorrect type.
|
||||||
|
for (y_start..y_end) |y| tile_surfaces[y][z_end] = 0;
|
||||||
}
|
}
|
||||||
// todo: scan tiles around quad surface for ambient occlusion
|
// todo: scan tiles around quad surface for ambient occlusion
|
||||||
y2 -= 1;
|
const raw_quad = pack_raw_quad(@floatFromInt(raw_x), y_start, y_end, z_start, z_end, sign, d, surface);
|
||||||
z2 -= 1;
|
|
||||||
tile_surfaces[y][z] = 0;
|
|
||||||
const raw_quad = pack_raw_quad(y, y2, z, z2, sign, d, surface, xf);
|
|
||||||
try raw_quads.append(raw_quad);
|
try raw_quads.append(raw_quad);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -290,7 +295,7 @@ pub const Chunk = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create mesh.
|
// Create mesh using the buffers.
|
||||||
var mesh = raylib.Mesh{
|
var mesh = raylib.Mesh{
|
||||||
.triangleCount = triangle_count,
|
.triangleCount = triangle_count,
|
||||||
.vertexCount = triangle_count * 3,
|
.vertexCount = triangle_count * 3,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue