Skip to content

Commit

Permalink
Renames mconv to zero-convert and adds a verb mode. This is now a gen…
Browse files Browse the repository at this point in the history
…eral purpose converter for zero-graphics
  • Loading branch information
Felix "xq" Queißner committed Oct 17, 2021
1 parent cb064ce commit dc6dfca
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 49 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ Comes with a pixel-perfect 2D renderer and maybe some day even with a bit of a 3

The CI coverage currently looks like this:

| · | Windows | macOS | Linux |
| ----------- | ------- | ----- | ----- |
| Desktop ||||
| WebAssembly ||||
| Android ||||
| `zero-init` ||||
| `mconv` ||||
| · | Windows | macOS | Linux |
| -------------- | ------- | ----- | ----- |
| Desktop ||||
| WebAssembly ||||
| Android ||||
| `zero-init` ||||
| `zero-convert` ||||

Status: [![Nightly Build](https://github.com/MasterQ32/zero-graphics/actions/workflows/nightly.yml/badge.svg)](https://github.com/MasterQ32/zero-graphics/actions/workflows/nightly.yml)

Expand Down
6 changes: 3 additions & 3 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ pub fn build(b: *std.build.Builder) !void {
}

{
const converter_api = b.addTranslateC(.{ .path = "tools/modelconv/api.h" });
const converter_api = b.addTranslateC(.{ .path = "tools/zero-convert/api.h" });

const converter = b.addExecutable("mconv", "tools/modelconv/main.zig");
converter.addCSourceFile("tools/modelconv/converter.cpp", &[_][]const u8{
const converter = b.addExecutable("zero-convert", "tools/zero-convert/main.zig");
converter.addCSourceFile("tools/zero-convert/converter.cpp", &[_][]const u8{
"-std=c++17",
"-Wall",
"-Wextra",
Expand Down
File renamed without changes.
File renamed without changes.
136 changes: 98 additions & 38 deletions tools/modelconv/main.zig → tools/zero-convert/main.zig
Original file line number Diff line number Diff line change
@@ -1,31 +1,75 @@
//!
//! zero-convert model --dynamic --output=/tmp/meshes.z3d /game/foo/bar.fbx
//! zero-convert texture --output /tmp/graphic.ztex /game/foo/bam.png
//! zero-convert sound --output /tmp/foo.zsnd /game/foo/bam.ogg
//! zero-convert music --output /tmp/foo.zmus /bla/blub/tmp.ogg
//! zero-convert animation --output /tmp/foo.zani /bla/blub/tmp.fbx
//!

const std = @import("std");
const api = @import("api");
const z3d = @import("z3d");
const args_parser = @import("args");

const CliArgs = struct {
output: ?[]const u8 = null,
dynamic: bool = false,
help: bool = false,
@"test": bool = false,

pub const shorthands = .{
.o = "output",
.h = "help",
};
};

const ModelArgs = struct {
dynamic: bool = false,

pub const shorthands = .{
.d = "dynamic",
};
};

fn printUsage(writer: anytype) !void {
const Verbs = union(enum) {
help: struct {},
model: ModelArgs,
texture: struct {},
sound: struct {},
music: struct {},
animation: struct {},
};

fn printUsage(exe_name: []const u8, writer: anytype) !void {
try writer.print("{s}", .{std.fs.path.basename(exe_name)});
try writer.writeAll(
\\mconv - convert 3d models to zero-graphics format
\\ - convert assets into the zero-graphics format
\\
\\Usage:
\\ mconv [--help] [--output <file>] [--dynamic] [--test] <input file>
\\
);
try writer.print(" {s}", .{std.fs.path.basename(exe_name)});
try writer.writeAll(
\\ <verb> [--help] [--output <file>] [--test] <input file>
\\ -h, --help Prints this help and succeeds.
\\ -o, --output <file> Writes the file to <file>. Otherwise, the extension of the input file is changed to .z3d
\\ -d, --dynamic Converts the model as a dynamic model with skinning information. Those models are usually somewhat larger, but can be animated.
\\ --test Does not write the output file, but will still perform the model conversion. This can be used to check if a model is convertible.
\\ -o, --output <file> Writes the file to <file>. Otherwise, the extension of the input file is changed to the right extension and will be placed next to the input file.
\\ --test Does not write the output file, but will still perform the conversion. This can be used to check if a file is convertible.
\\
\\Verbs:
\\ model [--dynamic]
\\ Converts a 3D model into the z3d format.
\\ -d, --dynamic Converts the model as a dynamic model with skinning information. Those models are usually somewhat larger, but can be animated.
\\
\\ texture
\\ Converts a texture/image file into the ztex format.
\\
\\ sound
\\ Converts a short sound file into the zsnd format.
\\
\\ music
\\ Converts a long sound file into the zmus format.
\\
\\ animation
\\ Converts the animations from a 3D model into the zani format.
\\
);
}
Expand All @@ -39,46 +83,62 @@ pub fn main() !u8 {
const stdout = std.io.getStdOut().writer();
const stderr = std.io.getStdErr().writer();

var cli = args_parser.parseForCurrentProcess(CliArgs, allocator, .print) catch return 1;
var cli = args_parser.parseWithVerbForCurrentProcess(CliArgs, Verbs, allocator, .print) catch return 1;
defer cli.deinit();

if (cli.options.help) {
try printUsage(stdout);
if (cli.options.help or (cli.verb != null and cli.verb.? == .help)) {
try printUsage(cli.executable_name.?, stdout);
return 0;
}
if (cli.positionals.len != 1) {
try printUsage(stderr);
if (cli.verb == null or cli.positionals.len != 1) {
try printUsage(cli.executable_name.?, stderr);
return 1;
}

const src_file = cli.positionals[0];
const src_file_name = cli.positionals[0];

const extension = switch (cli.verb.?) {
.help => unreachable, // we already printed the help text
.model => "z3d",
.texture => "ztex",
.sound => "zsnd",
.music => "zmus",
.animation => "zani",
};

var dst_file = std.ArrayList(u8).init(allocator);
defer dst_file.deinit();

if (cli.options.output) |dst| {
try dst_file.appendSlice(dst);
} else {
try dst_file.appendSlice(src_file);
const ext = std.fs.path.extension(src_file);
try dst_file.appendSlice(src_file_name);
const ext = std.fs.path.extension(src_file_name);
dst_file.shrinkRetainingCapacity(dst_file.items.len - ext.len);
try dst_file.appendSlice(".z3d");
try dst_file.appendSlice(extension);
}

var stream = Stream{
.target_buffer = std.ArrayList(u8).init(allocator),
};
defer stream.target_buffer.deinit();

if (!api.transformFile(src_file.ptr, &stream.mesh_stream, if (cli.options.dynamic) api.dynamic_geometry else api.static_geometry)) {
return 1;
var final_buffer = std.ArrayList(u8).init(allocator);
defer final_buffer.deinit();

switch (cli.verb.?) {
.model => |flags| {
var stream = MeshStream{
.target_buffer = &final_buffer,
};

if (!api.transformFile(src_file_name.ptr, &stream.mesh_stream, if (flags.dynamic) api.dynamic_geometry else api.static_geometry)) {
return 1;
}
},
else => {
try stderr.print("{s} conversion is not implemented yet!\n", .{std.meta.tagName(cli.verb.?)});
return 1;
},
}

if (!cli.options.@"test") {
try std.fs.cwd().writeFile(
dst_file.items,
stream.target_buffer.items,
);
try std.fs.cwd().writeFile(dst_file.items, final_buffer.items);
}

return 0;
Expand All @@ -96,7 +156,7 @@ export fn printWarningMessage(text: [*]const u8, length: usize) void {
std.log.warn("{s}", .{text[0..length]});
}

const Stream = struct {
const MeshStream = struct {
mesh_stream: api.MeshStream = .{
.writeStaticHeader = writeStaticHeader,
.writeVertex = writeVertex,
Expand All @@ -105,7 +165,7 @@ const Stream = struct {
},

failed: ?anyerror = null,
target_buffer: std.ArrayList(u8),
target_buffer: *std.ArrayList(u8),

vertex_count: usize = 0,
index_count: usize = 0,
Expand All @@ -115,29 +175,29 @@ const Stream = struct {
index_offset: usize = 0,
mesh_offset: usize = 0,

fn setError(self: *Stream, err: anyerror) void {
fn setError(self: *MeshStream, err: anyerror) void {
self.failed = err;
}

fn vertexOffset(self: Stream) usize {
fn vertexOffset(self: MeshStream) usize {
_ = self;
return 24;
}

fn indexOffset(self: Stream) usize {
fn indexOffset(self: MeshStream) usize {
return self.vertexOffset() + 32 * self.vertex_count;
}

fn meshOffset(self: Stream) usize {
fn meshOffset(self: MeshStream) usize {
return self.indexOffset() + 2 * self.index_count;
}

fn fileSize(self: Stream) usize {
fn fileSize(self: MeshStream) usize {
return self.meshOffset() + 128 * self.mesh_count;
}

fn writeStaticHeader(mesh_stream: ?*api.MeshStream, vertices: usize, indices: usize, ranges: usize) callconv(.C) void {
const stream = @fieldParentPtr(Stream, "mesh_stream", mesh_stream.?);
const stream = @fieldParentPtr(MeshStream, "mesh_stream", mesh_stream.?);
if (stream.failed != null)
return;

Expand Down Expand Up @@ -169,7 +229,7 @@ const Stream = struct {
}

fn writeVertex(mesh_stream: ?*api.MeshStream, x: f32, y: f32, z: f32, nx: f32, ny: f32, nz: f32, u: f32, v: f32) callconv(.C) void {
const stream = @fieldParentPtr(Stream, "mesh_stream", mesh_stream.?);
const stream = @fieldParentPtr(MeshStream, "mesh_stream", mesh_stream.?);
if (stream.failed != null)
return;

Expand All @@ -190,7 +250,7 @@ const Stream = struct {
}

fn writeFace(mesh_stream: ?*api.MeshStream, index0: u16, index1: u16, index2: u16) callconv(.C) void {
const stream = @fieldParentPtr(Stream, "mesh_stream", mesh_stream.?);
const stream = @fieldParentPtr(MeshStream, "mesh_stream", mesh_stream.?);
if (stream.failed != null)
return;

Expand All @@ -203,7 +263,7 @@ const Stream = struct {
}

fn writeMeshRange(mesh_stream: ?*api.MeshStream, offset: usize, length: usize, texture: ?[*:0]const u8) callconv(.C) void {
const stream = @fieldParentPtr(Stream, "mesh_stream", mesh_stream.?);
const stream = @fieldParentPtr(MeshStream, "mesh_stream", mesh_stream.?);
if (stream.failed != null)
return;

Expand Down
2 changes: 1 addition & 1 deletion vendor/ZigAndroidTemplate

0 comments on commit dc6dfca

Please sign in to comment.