Simplify build.zig, support installing multiple asset outputs

This commit is contained in:
sergeypdev 2024-02-23 21:27:08 +04:00
parent 672bce7fe6
commit 756f4fa6f9
4 changed files with 79 additions and 124 deletions

131
build.zig
View File

@ -146,12 +146,12 @@ pub fn build(b: *Build) void {
}
const asset_extensions = [_][]const u8{
".obj",
".glsl",
".prog",
".png",
".jpg",
".exr",
"obj",
"glsl",
"prog",
"png",
"jpg",
"exr",
};
// Find all assets and cook them using assetc
@ -168,107 +168,40 @@ fn buildAssets(b: *std.Build, install_assetc_step: *Step, step: *Step, assetc: *
defer walker.deinit();
while (try walker.next()) |entry| {
if (std.mem.endsWith(u8, entry.basename, ".obj")) {
const run_assetc = b.addRunArtifact(assetc);
gen_asset_manifest.addAssetListFile(run_assetc.captureStdOut());
run_assetc.step.dependOn(install_assetc_step);
const ext_with_dot = std.fs.path.extension(entry.basename);
if (ext_with_dot.len == 0) continue;
run_assetc.addPathDir(b.pathFromRoot("libs/ispc_texcomp/lib"));
const ext = ext_with_dot[1..];
run_assetc.addFileArg(.{ .path = b.pathJoin(&.{ path, entry.path }) });
const out_name = try std.mem.concat(
b.allocator,
u8,
&.{ std.fs.path.stem(entry.basename), ".mesh" },
);
const compiled_file = run_assetc.addOutputFileArg(out_name);
const out_path = b.pathJoin(&.{
path,
std.fs.path.dirname(entry.path) orelse "",
out_name,
});
const install_asset = b.addInstallFileWithDir(
compiled_file,
.prefix,
out_path,
);
step.dependOn(&install_asset.step);
var is_known_ext = false;
for (asset_extensions) |known_ext| {
if (std.mem.eql(u8, known_ext, ext)) {
is_known_ext = true;
break;
}
}
if (!is_known_ext) continue;
if (std.mem.endsWith(u8, entry.basename, ".glsl")) {
const run_assetc = b.addRunArtifact(assetc);
run_assetc.step.dependOn(install_assetc_step);
const run_assetc = b.addRunArtifact(assetc);
gen_asset_manifest.addAssetListFile(run_assetc.captureStdOut());
run_assetc.step.dependOn(install_assetc_step);
gen_asset_manifest.addAssetListFile(run_assetc.captureStdOut());
run_assetc.addPathDir(b.pathFromRoot("libs/ispc_texcomp/lib"));
run_assetc.addPathDir(b.pathFromRoot("libs/ispc_texcomp/lib"));
// First argument, input path relative to base assets dir
run_assetc.addArg(b.dupe(entry.path));
// Absolute input file arg, this will add it to step deps, cache and all that good stuff
run_assetc.addFileArg(.{ .path = b.pathJoin(&.{ path, entry.path }) });
run_assetc.addFileArg(.{ .path = b.pathJoin(&.{ path, entry.path }) });
const compiled_file = run_assetc.addOutputFileArg(b.dupe(entry.basename));
// Generated output dir. Output asset(s) will be placed there at the same relative path as input
const result_dir = run_assetc.addOutputFileArg("assets");
const out_path = b.pathJoin(&.{
path,
entry.path,
});
const install_asset = b.addInstallFileWithDir(
compiled_file,
.prefix,
out_path,
);
step.dependOn(&install_asset.step);
}
// Shader program
if (std.mem.endsWith(u8, entry.basename, ".prog")) {
const run_assetc = b.addRunArtifact(assetc);
run_assetc.step.dependOn(install_assetc_step);
gen_asset_manifest.addAssetListFile(run_assetc.captureStdOut());
run_assetc.addPathDir(b.pathFromRoot("libs/ispc_texcomp/lib"));
run_assetc.addFileArg(.{ .path = b.pathJoin(&.{ path, entry.path }) });
const compiled_file = run_assetc.addOutputFileArg(b.dupe(entry.basename));
const out_path = b.pathJoin(&.{
path,
entry.path,
});
const install_asset = b.addInstallFileWithDir(
compiled_file,
.prefix,
out_path,
);
step.dependOn(&install_asset.step);
}
if (std.mem.endsWith(u8, entry.basename, ".png") or std.mem.endsWith(u8, entry.basename, ".jpg") or std.mem.endsWith(u8, entry.basename, ".exr")) {
const run_assetc = b.addRunArtifact(assetc);
run_assetc.step.dependOn(install_assetc_step);
run_assetc.addPathDir(b.pathFromRoot("libs/ispc_texcomp/lib"));
gen_asset_manifest.addAssetListFile(run_assetc.captureStdOut());
run_assetc.addFileArg(.{ .path = b.pathJoin(&.{ path, entry.path }) });
const out_name = try std.mem.concat(
b.allocator,
u8,
&.{ std.fs.path.stem(entry.basename), ".tex" },
);
const compiled_file = run_assetc.addOutputFileArg(out_name);
const out_path = b.pathJoin(&.{
path,
std.fs.path.dirname(entry.path) orelse "",
out_name,
});
const install_asset = b.addInstallFileWithDir(
compiled_file,
.prefix,
out_path,
);
step.dependOn(&install_asset.step);
}
const install_assets = b.addInstallDirectory(.{
.source_dir = result_dir,
.install_dir = .prefix,
.install_subdir = path,
});
step.dependOn(&install_assets.step);
}
return asset_manifest_file;

View File

@ -119,7 +119,7 @@ pub fn begin(self: *Render) void {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.mesh).program);
gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.mesh).program);
gl.bindVertexArray(self.mesh_vao);
if (self.gl_fences[self.tripple_buffer_index]) |fence| {

View File

@ -55,7 +55,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
// Random bytes to make WriteFile unique. Refresh this with
// new random bytes when GenerateAssetManifest implementation is modified
// in a non-backwards-compatible way.
man.hash.add(@as(u32, 0xd767ee68));
man.hash.add(@as(u32, 0xd767ee71));
// TODO: sort generated asset lists to make sure cache is predictable
@ -195,14 +195,14 @@ const NestedAssetDef = union(enum) {
var iter = try std.fs.path.componentIterator(path.getPath());
const filename = iter.last().?.name;
_ = iter.first();
// Skip first one because it's always "assets"
_ = iter.next();
var current = &self.path;
while (iter.next()) |comp| {
std.log.debug("NestedAssetDef comp next {s}\n", .{comp.name});
if (comp.name.ptr == filename.ptr) break;
const gop = try current.getOrPut(allocator, comp.name);
std.log.debug("NestedAssetDef put path {s}\n", .{comp.name});
if (!gop.found_existing) {
gop.value_ptr.* = NestedAssetDef{ .path = .{} };
}
@ -216,6 +216,7 @@ const NestedAssetDef = union(enum) {
}
try gop.value_ptr.put(allocator, .{ .simple = sub_path }, asset_list_entry);
} else {
std.log.debug("NestedAssetDef put filename {s}\n", .{std.fs.path.stem(filename)});
try current.put(allocator, std.fs.path.stem(filename), NestedAssetDef{
.asset = asset_list_entry,
});

View File

@ -38,40 +38,51 @@ pub fn resolveAssetTypeByExtension(path: []const u8) ?AssetType {
pub fn main() !void {
const allocator = std.heap.c_allocator;
const argv = std.os.argv;
if (argv.len < 3) {
std.log.err("usage assetc <basedir> <input> <output>\n", .{});
if (argv.len < 4) {
std.log.err("usage assetc <rel_path> <input> <output>\n", .{});
return error.MissingArgs;
}
const input = argv[argv.len - 2];
const output = std.mem.span(argv[argv.len - 1]);
const rel_input = std.mem.span(argv[argv.len - 3]);
const abs_input = std.mem.span(argv[argv.len - 2]);
const output_dir_path = std.mem.span(argv[argv.len - 1]);
var cwd_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
const cwd_path = try std.os.getcwd(&cwd_buf);
const build_root_rel_input = try std.fs.path.relative(allocator, cwd_path, std.mem.span(input));
const cwd_rel_input = try std.fs.path.relative(allocator, cwd_path, abs_input);
const cwd_rel_output_dir = try std.fs.path.relative(allocator, cwd_path, output_dir_path);
const asset_type = resolveAssetTypeByExtension(std.mem.span(input)) orelse return error.UnknownAssetType;
// Generated output dir
var output_dir = blk: {
var base_output_dir = try std.fs.cwd().makeOpenPath(cwd_rel_output_dir, .{});
defer base_output_dir.close();
break :blk try base_output_dir.makeOpenPath(std.fs.path.dirname(rel_input) orelse ".", .{});
};
defer output_dir.close();
const asset_type = resolveAssetTypeByExtension(abs_input) orelse return error.UnknownAssetType;
switch (asset_type) {
.Mesh => try processMesh(allocator, input, output),
.Shader => try std.fs.copyFileAbsolute(std.mem.span(input), output, .{}),
.ShaderProgram => try processShaderProgram(allocator, std.mem.span(input), output),
.Texture => try processTexture(allocator, input, output, false),
.Mesh => try processMesh(allocator, abs_input, output_dir),
.Shader => try std.fs.Dir.copyFile(std.fs.cwd(), abs_input, output_dir, std.fs.path.basename(rel_input), .{}),
.ShaderProgram => try processShaderProgram(allocator, abs_input, output_dir),
.Texture => try processTexture(allocator, abs_input, output_dir, false),
}
const out_writer = std.io.getStdOut().writer();
try asset_list.writeAssetListEntryText(out_writer, .{
.type = asset_type,
.src_path = .{ .simple = build_root_rel_input },
.dst_path = output,
.src_path = .{ .simple = cwd_rel_input }, // TODO: remove assets prefix
.dst_path = cwd_rel_output_dir,
});
}
fn processMesh(allocator: std.mem.Allocator, input: [*:0]const u8, output: []const u8) !void {
fn processMesh(allocator: std.mem.Allocator, input: []const u8, output_dir: std.fs.Dir) !void {
const maybe_scene: ?*const c.aiScene = @ptrCast(c.aiImportFile(
input,
input.ptr,
c.aiProcess_CalcTangentSpace | c.aiProcess_Triangulate | c.aiProcess_JoinIdenticalVertices | c.aiProcess_SortByPType | c.aiProcess_GenNormals,
));
if (maybe_scene == null) {
@ -152,7 +163,9 @@ fn processMesh(allocator: std.mem.Allocator, input: [*:0]const u8, output: []con
.indices = indices,
};
const out_file = try std.fs.createFileAbsolute(output, .{});
const out_name = try changeExtensionAlloc(allocator, input, AssetType.Mesh.ext());
const out_file = try output_dir.createFile(out_name, .{});
defer out_file.close();
var buf_writer = std.io.bufferedWriter(out_file.writer());
@ -164,7 +177,7 @@ fn processMesh(allocator: std.mem.Allocator, input: [*:0]const u8, output: []con
try buf_writer.flush();
}
fn processShaderProgram(allocator: std.mem.Allocator, absolute_input: []const u8, output: []const u8) !void {
fn processShaderProgram(allocator: std.mem.Allocator, absolute_input: []const u8, output_dir: std.fs.Dir) !void {
var cwd_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
const cwd_path = try std.os.getcwd(&cwd_buf);
@ -198,7 +211,7 @@ fn processShaderProgram(allocator: std.mem.Allocator, absolute_input: []const u8
return error.InvalidShaderPath;
}
const out_file = try std.fs.createFileAbsolute(output, .{});
const out_file = try output_dir.createFile(std.fs.path.basename(absolute_input), .{});
defer out_file.close();
var buf_writer = std.io.bufferedWriter(out_file.writer());
@ -212,11 +225,11 @@ const MipLevel = struct {
out_data: []const u8 = &.{},
};
fn processTexture(allocator: std.mem.Allocator, input: [*:0]const u8, output: []const u8, hdr: bool) !void {
fn processTexture(allocator: std.mem.Allocator, input: []const u8, output_dir: std.fs.Dir, hdr: bool) !void {
_ = hdr; // autofix
// For tex.norm.png - this will be ".norm"
const sub_ext = std.fs.path.extension(std.fs.path.stem(std.mem.span(input)));
const sub_ext = std.fs.path.extension(std.fs.path.stem(input));
const format = if (std.mem.eql(u8, sub_ext, ".norm")) formats.Texture.Format.bc5 else formats.Texture.Format.bc7;
var width_int: c_int = undefined;
@ -224,7 +237,7 @@ fn processTexture(allocator: std.mem.Allocator, input: [*:0]const u8, output: []
var comps: c_int = undefined;
c.stbi_set_flip_vertically_on_load(1);
const rgba_data_c = c.stbi_load(input, &width_int, &height_int, &comps, 4);
const rgba_data_c = c.stbi_load(input.ptr, &width_int, &height_int, &comps, 4);
if (rgba_data_c == null) {
return error.ImageLoadError;
}
@ -308,7 +321,8 @@ fn processTexture(allocator: std.mem.Allocator, input: [*:0]const u8, output: []
},
.data = out_data,
};
const out_file = try std.fs.createFileAbsolute(output, .{});
const out_name = try changeExtensionAlloc(allocator, input, AssetType.Texture.ext());
const out_file = try output_dir.createFile(out_name, .{});
defer out_file.close();
var buf_writer = std.io.bufferedWriter(out_file.writer());
@ -508,3 +522,10 @@ inline fn storeColorVec4(pixel: []u8, vec: @Vector(4, f32)) void {
pixel[2] = @intFromFloat(out[2]);
pixel[3] = @intFromFloat(out[3]);
}
fn changeExtensionAlloc(allocator: std.mem.Allocator, input: []const u8, new_ext: []const u8) ![]u8 {
const input_basename = std.fs.path.basename(input);
const ext = std.fs.path.extension(input_basename);
const name_without_ext = input_basename[0 .. input_basename.len - ext.len];
return try std.mem.concat(allocator, u8, &.{ name_without_ext, ".", new_ext });
}