Files
voxel-game/pipeline/main.zig

161 lines
5.7 KiB
Zig
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const std = @import("std");
const zstbi = @import("zstbi");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
zstbi.init(allocator);
defer zstbi.deinit();
const cwd = std.fs.cwd();
var assets_dir = openDirOrExit(cwd, "assets", .{ .iterate = true });
defer assets_dir.close();
var library_dir = openDirOrExit(cwd, "library", .{});
defer library_dir.close();
visit(assets_dir, library_dir, allocator);
}
fn visit(assets_dir: std.fs.Dir, library_dir: std.fs.Dir, allocator: std.mem.Allocator) void {
var it = assets_dir.iterate();
while (it.next() catch |err| blk: {
std.log.err("Directory iteration interrupted due to an error: {s}", .{@errorName(err)});
break :blk null;
}) |entry| {
if (entry.kind == .directory) {
var assets_subdir = assets_dir.openDir(entry.name, .{ .iterate = true }) catch |err| {
std.log.warn("Skipping directory \"{s}\" due to an error: {s}", .{ entry.name, @errorName(err) });
continue;
};
defer assets_subdir.close();
library_dir.makeDir(entry.name) catch |err| switch (err) {
error.PathAlreadyExists => {
// This is fine
},
else => {
std.log.warn("Skipping directory \"{s}\" due to an error while creating corresponding library directory: {s}", .{ entry.name, @errorName(err) });
continue;
},
};
var library_subdir = library_dir.openDir(entry.name, .{}) catch |err| {
std.log.warn("Skipping directory \"{s}\" due to an error while opening corresponding library directory: {s}", .{ entry.name, @errorName(err) });
continue;
};
defer library_subdir.close();
visit(assets_subdir, library_subdir, allocator);
continue;
}
if (entry.kind != .file) {
std.log.warn("Skipping \"{s}\", which is not a file nor a directory.", .{entry.name});
continue;
}
std.log.info("Processing \"{s}\"...", .{entry.name});
const infile = assets_dir.openFile(entry.name, .{}) catch |err| {
std.log.err("Could not open \"{s}\" file: {s}", .{ entry.name, @errorName(err) });
continue;
};
defer infile.close();
const inbuf = infile.readToEndAlloc(allocator, std.math.maxInt(usize)) catch |err| {
std.log.err("Could not read \"{s}\" file contents due to an error: {s}", .{ entry.name, @errorName(err) });
continue;
};
defer allocator.free(inbuf);
var img = zstbi.Image.loadFromMemory(inbuf, 4) catch |err| {
std.log.err("Error reading \"{s}\" as an image file: {s}", .{ entry.name, @errorName(err) });
continue;
};
defer img.deinit();
std.log.debug("size: {}×{} | components: {}", .{ img.width, img.height, img.num_components });
const grid_w = 4;
const grid_h = 4;
const tile_count = grid_w * grid_h;
const tile_w = std.math.divExact(u32, img.width, grid_w) catch |err| {
std.log.err("Cannot divide image width ({}) by {}: {s}", .{ img.width, grid_w, @errorName(err) });
continue;
};
const tile_h = std.math.divExact(u32, img.height, grid_h) catch |err| {
std.log.err("Cannot divide image height ({}) by {}: {s}", .{ img.height, grid_h, @errorName(err) });
continue;
};
std.log.debug("tile size: {}×{}", .{ tile_w, tile_h });
const outbuf = allocator.alloc(u8, 4 * tile_w * tile_h * tile_count) catch {
std.log.err("Ran out of memory while trying to allocate output buffer", .{});
continue;
};
defer allocator.free(outbuf);
rearrange(grid_w, grid_h, tile_w, tile_h, img.data, outbuf);
const out_name = std.fs.path.stem(entry.name);
library_dir.writeFile(.{
.data = outbuf,
.sub_path = out_name,
}) catch |err| {
std.log.err("Couldn't write \"{s}\" file corresponding to \"{s}\" asset file: {s}", .{ out_name, entry.name, @errorName(err) });
};
}
}
fn rearrange(grid_w: u32, grid_h: u32, tile_w: u32, tile_h: u32, inbuf: []const u8, outbuf: []u8) void {
std.log.debug("rearrange: {}×{} grid of {}×{} tiles", .{ grid_w, grid_h, tile_w, tile_h });
const row_size = 4 * tile_w;
const row_stride = row_size * grid_w;
const tile_stride = row_stride * tile_h;
std.debug.assert(inbuf.len == tile_stride * grid_h);
std.debug.assert(outbuf.len == tile_stride * grid_h);
var outptr: usize = 0;
var tile_y: u32 = 0;
while (tile_y < grid_h) : (tile_y += 1) {
const tile_byte_offset = tile_y * tile_stride;
var tile_x: u32 = 0;
while (tile_x < grid_w) : (tile_x += 1) {
const column_byte_offset = tile_x * row_size;
var row: u32 = 0;
while (row < tile_h) : (row += 1) {
const row_byte_offset = row * row_stride + tile_byte_offset;
const byte_offset = row_byte_offset + column_byte_offset;
@memcpy(
outbuf[outptr .. outptr + row_size],
inbuf[byte_offset .. byte_offset + row_size],
);
outptr += row_size;
}
}
}
}
fn openDirOrExit(dir: std.fs.Dir, sub_path: []const u8, args: std.fs.Dir.OpenOptions) std.fs.Dir {
return dir.openDir(sub_path, args) catch |err| {
std.log.err("Could not open \"{s}\" directory: {s}", .{ sub_path, @errorName(err) });
std.posix.exit(1);
};
}