240 lines
7.1 KiB
Zig
240 lines
7.1 KiB
Zig
const MeshConfig = struct {
|
|
info: CookInfo = .{ .assetType = "Mesh" }, // there must always be a CookInfo field
|
|
sourceType: []const u8 = "obj",
|
|
animated: bool = false,
|
|
};
|
|
|
|
const extList = [_][]const u8{ "gltf", "obj", "glb" };
|
|
pub fn generateFunction(allocator: std.mem.Allocator, path: []const u8, out: *std.ArrayList(u8)) GenerateError!void {
|
|
_ = allocator;
|
|
out.clearRetainingCapacity();
|
|
const ext = core.getFileExtension(path)[1..];
|
|
|
|
var config: MeshConfig = .{};
|
|
|
|
for (extList) |e| {
|
|
if (std.mem.eql(u8, e, ext)) {
|
|
config.sourceType = e;
|
|
|
|
if (std.mem.eql(u8, e, "glb")) {
|
|
config.sourceType = "gltf";
|
|
}
|
|
}
|
|
}
|
|
|
|
std.json.stringify(
|
|
config,
|
|
.{ .whitespace = .indent_4 },
|
|
out.writer(),
|
|
) catch return GenerateError.UnableToGenerate;
|
|
}
|
|
|
|
fn cookObj(allocator: std.mem.Allocator, dir: std.fs.Dir, path: []const u8) cook.CookResult {
|
|
const rawFileBytes = cook.loadFileAlloc(allocator, dir, path) catch unreachable;
|
|
defer allocator.free(rawFileBytes);
|
|
|
|
var out = std.ArrayList(u8).init(allocator);
|
|
|
|
var vertices = std.ArrayList(Vertex).init(allocator);
|
|
defer vertices.deinit();
|
|
|
|
var objs = obj.loadObjBytes(rawFileBytes, allocator) catch unreachable;
|
|
defer objs.deinit();
|
|
|
|
if (objs.meshes.items.len > 0) {
|
|
mesh.loadObjMeshVertices(&vertices, objs.meshes.items[0]) catch unreachable;
|
|
for (vertices.items) |vert| {
|
|
out.appendSlice(&@as([@sizeOf(Vertex)]u8, @bitCast(vert))) catch unreachable;
|
|
}
|
|
|
|
return .{
|
|
.bytes = out,
|
|
.result = .Success,
|
|
};
|
|
} else {
|
|
return .{
|
|
.bytes = out,
|
|
.result = .Failure,
|
|
};
|
|
}
|
|
}
|
|
|
|
fn ensureGltf2ozz(allocator: std.mem.Allocator) !void {
|
|
const suffix = if (builtin.os.tag == .windows) ".exe" else "";
|
|
std.fs.cwd().access("zig-out/tools/gltf2ozz" ++ suffix, .{}) catch {
|
|
const argv: []const []const u8 = &.{ "zig", "build", "tools" };
|
|
|
|
core.engine_log("gltf2ozz missing, building it...", .{});
|
|
|
|
var child = std.process.Child.init(argv, allocator);
|
|
child.stdin_behavior = .Ignore;
|
|
child.stdout_behavior = .Pipe;
|
|
child.stderr_behavior = .Pipe;
|
|
child.cwd = ".";
|
|
|
|
switch (try child.spawnAndWait()) {
|
|
.Exited => |value| {
|
|
if (value == 0) {
|
|
core.engine_log("gltf2ozz built", .{});
|
|
} else {
|
|
core.engine_logs("unable to build gltf2ozz");
|
|
}
|
|
},
|
|
.Signal => {
|
|
core.engine_logs("unable to build gltf2ozz");
|
|
},
|
|
.Stopped => {},
|
|
.Unknown => {
|
|
unreachable;
|
|
},
|
|
}
|
|
|
|
return;
|
|
};
|
|
|
|
core.engine_log("gltf2ozz found", .{});
|
|
}
|
|
|
|
fn cookAnimations(allocator: std.mem.Allocator, dir: std.fs.Dir, path: []const u8, config: MeshConfig) !void {
|
|
_ = config;
|
|
|
|
// 1. check if it has an associated .ozzconfig file.
|
|
|
|
const gltf2OzzAbs = try std.fs.cwd().realpathAlloc(allocator, "zig-out/tools/gltf2ozz.exe");
|
|
defer allocator.free(gltf2OzzAbs);
|
|
|
|
const ozzconfig = try std.fmt.allocPrint(allocator, "{s}.ozzconfig", .{path});
|
|
defer allocator.free(ozzconfig);
|
|
|
|
const fileArg = try std.fmt.allocPrint(allocator, "--file={s}", .{core.getBasePath(path)});
|
|
defer allocator.free(fileArg);
|
|
|
|
const configArg = try std.fmt.allocPrint(allocator, "--config_file={s}", .{core.getBasePath(ozzconfig)});
|
|
defer allocator.free(configArg);
|
|
|
|
// todo, fix this later, idrc right now.
|
|
const newConfigArg = try std.fmt.allocPrint(allocator, "--config_dump_reference={s}", .{core.getBasePath(ozzconfig)});
|
|
defer allocator.free(newConfigArg);
|
|
|
|
const absFile = try dir.realpathAlloc(allocator, path);
|
|
defer allocator.free(absFile);
|
|
|
|
var argv: []const []const u8 = &.{
|
|
gltf2OzzAbs,
|
|
fileArg,
|
|
configArg,
|
|
};
|
|
|
|
dir.access(ozzconfig, .{}) catch {
|
|
argv = &.{
|
|
gltf2OzzAbs,
|
|
fileArg,
|
|
newConfigArg,
|
|
};
|
|
|
|
core.engine_log("creating ozz config for file, marked as animated but no animation data", .{});
|
|
};
|
|
|
|
// std.debug.print("{s} {s} {s} cwd = {s}\n", .{ argv[0], argv[1], argv[2], core.getFolder(absFile) });
|
|
|
|
const result = try std.process.Child.run(.{
|
|
.argv = argv,
|
|
.allocator = allocator,
|
|
.cwd = core.getFolder(absFile),
|
|
.max_output_bytes = 150 * 1024 * 1024,
|
|
});
|
|
|
|
defer allocator.free(result.stdout);
|
|
defer allocator.free(result.stderr);
|
|
|
|
var success: bool = true;
|
|
switch (result.term) {
|
|
.Exited => |value| {
|
|
if (value != 0) {
|
|
success = false;
|
|
}
|
|
},
|
|
.Signal => {
|
|
success = false;
|
|
},
|
|
.Stopped => {
|
|
success = false;
|
|
// no-op should be ok?
|
|
},
|
|
.Unknown => {
|
|
unreachable;
|
|
},
|
|
}
|
|
|
|
if (success) {
|
|
core.engine_log("generated animations for {s}", .{path});
|
|
} else {
|
|
core.engine_log("error generating animations {s} stdout:\n{s}\n stderr:{s}\n", .{ path, result.stdout, result.stderr });
|
|
}
|
|
// 2. if so, run it through gltf2ozz with that file.
|
|
}
|
|
|
|
fn cookGltf(allocator: std.mem.Allocator, dir: std.fs.Dir, path: []const u8, config: MeshConfig) cook.CookResult {
|
|
core.engine_logs("gltf cooking not implemeted");
|
|
const out = std.ArrayList(u8).init(allocator);
|
|
|
|
// check if it's animated. if it's animated, then invoke gltf2ozz and create a .ozzconfig file and
|
|
// make a subfolder called
|
|
|
|
if (config.animated) {
|
|
// if gltf2ozz isn't there then we have to call zig build tools
|
|
ensureGltf2ozz(allocator) catch unreachable;
|
|
|
|
cookAnimations(allocator, dir, path, config) catch unreachable;
|
|
}
|
|
|
|
return .{ .bytes = out, .result = .Failure };
|
|
}
|
|
|
|
pub fn cookFunction(
|
|
allocator: std.mem.Allocator,
|
|
dir: std.fs.Dir,
|
|
path: []const u8,
|
|
params: cook.CookParams,
|
|
) cook.CookResult {
|
|
core.engine_log("{s}", .{params.cookFileName});
|
|
const fc = cook.loadFileAlloc(allocator, dir, params.cookFileName) catch unreachable;
|
|
defer allocator.free(fc);
|
|
|
|
const config = std.json.parseFromSlice(MeshConfig, allocator, fc[0 .. fc.len - 1], .{}) catch unreachable;
|
|
defer config.deinit();
|
|
|
|
if (std.mem.eql(u8, config.value.sourceType, "obj")) {
|
|
return cookObj(allocator, dir, path);
|
|
} else {
|
|
return cookGltf(allocator, dir, path, config.value);
|
|
}
|
|
}
|
|
|
|
pub fn initCooker(allocator: std.mem.Allocator) !void {
|
|
_ = allocator;
|
|
const registry = assets.cook.getRegistry();
|
|
|
|
try registry.install("Mesh", generateFunction, cookFunction, &.{
|
|
".obj",
|
|
".gltf",
|
|
".glb",
|
|
});
|
|
}
|
|
|
|
pub fn deinitCooker() void {
|
|
//
|
|
}
|
|
|
|
const std = @import("std");
|
|
const assets = @import("assets");
|
|
const cook = assets.cook;
|
|
const CookInfo = assets.cook.CookInfo;
|
|
const GenerateError = assets.cook.GenerateError;
|
|
const core = @import("core");
|
|
const obj = @import("objLoader");
|
|
const builtin = @import("builtin");
|
|
const mesh = @import("../mesh.zig");
|
|
const Mesh = mesh.Mesh;
|
|
const Vertex = mesh.MeshVertex;
|