Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 16 additions & 21 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23,34 +23,31 @@ pub fn build(b: *std.Build) void {
}

const options_module = options_step.createModule();

_ = b.addModule("root", .{
const zmesh_module = b.addModule("root", .{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "zmesh_options", .module = options_module },
},
});

const zmesh_lib = if (options.shared) blk: {
const lib = b.addSharedLibrary(.{
.name = "zmesh",
const zmesh_lib = b.addLibrary(.{
.name = "zmesh",
.linkage = if (options.shared) .dynamic else .static,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
});
}),
});

if (target.result.os.tag == .windows) {
lib.root_module.addCMacro("PAR_SHAPES_API", "__declspec(dllexport)");
lib.root_module.addCMacro("CGLTF_API", "__declspec(dllexport)");
lib.root_module.addCMacro("MESHOPTIMIZER_API", "__declspec(dllexport)");
lib.root_module.addCMacro("ZMESH_API", "__declspec(dllexport)");
}
if (options.shared and target.result.os.tag == .windows) {
zmesh_lib.root_module.addCMacro("PAR_SHAPES_API", "__declspec(dllexport)");
zmesh_lib.root_module.addCMacro("CGLTF_API", "__declspec(dllexport)");
zmesh_lib.root_module.addCMacro("MESHOPTIMIZER_API", "__declspec(dllexport)");
zmesh_lib.root_module.addCMacro("ZMESH_API", "__declspec(dllexport)");
}

break :blk lib;
} else b.addStaticLibrary(.{
.name = "zmesh",
.target = target,
.optimize = optimize,
});
b.installArtifact(zmesh_lib);

zmesh_lib.linkLibC();
Expand Down Expand Up @@ -93,9 +90,7 @@ pub fn build(b: *std.Build) void {

const tests = b.addTest(.{
.name = "zmesh-tests",
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
.root_module = zmesh_module,
});
b.installArtifact(tests);

Expand Down
136 changes: 1 addition & 135 deletions src/io.zig
Original file line number Diff line number Diff line change
@@ -1,145 +1,11 @@
const std = @import("std");
const assert = std.debug.assert;

const mem = @import("memory.zig");

/// Deprecated. Use `zmesh.io.zcgltf.parseAndLoadFile` instead.
pub const parseAndLoadFile = zcgltf.parseAndLoadFile;
/// Deprecated. Use `zmesh.io.zcgltf.freeData` instead.
pub const freeData = zcgltf.freeData;
/// Deprecated. Use `zmesh.io.zcgltf.appendMeshPrimitive` instead.
pub const appendMeshPrimitive = zcgltf.appendMeshPrimitive;

pub const zcgltf = struct {
const bindings = @import("zcgltf.zig");
const Data = bindings.Data;

pub usingnamespace bindings;

pub fn parseAndLoadFile(pathname: [:0]const u8) bindings.Error!*Data {
const options = bindings.Options{
.memory = .{
.alloc_func = mem.zmeshAllocUser,
.free_func = mem.zmeshFreeUser,
},
};

const data = try bindings.parseFile(options, pathname);
errdefer bindings.free(data);

try bindings.loadBuffers(options, data, pathname);

return data;
}

pub fn freeData(data: *Data) void {
bindings.free(data);
}

pub fn appendMeshPrimitive(
data: *Data,
mesh_index: u32,
prim_index: u32,
indices: *std.ArrayList(u32),
positions: *std.ArrayList([3]f32),
normals: ?*std.ArrayList([3]f32),
texcoords0: ?*std.ArrayList([2]f32),
tangents: ?*std.ArrayList([4]f32),
) !void {
assert(mesh_index < data.meshes_count);
assert(prim_index < data.meshes.?[mesh_index].primitives_count);

const mesh = &data.meshes.?[mesh_index];
const prim = &mesh.primitives[prim_index];

const num_vertices: u32 = @as(u32, @intCast(prim.attributes[0].data.count));
const num_indices: u32 = @as(u32, @intCast(prim.indices.?.count));

// Indices.
{
try indices.ensureTotalCapacity(indices.items.len + num_indices);

const accessor = prim.indices.?;
const buffer_view = accessor.buffer_view.?;

assert(accessor.stride == buffer_view.stride or buffer_view.stride == 0);
assert(buffer_view.buffer.data != null);

const data_addr = @as([*]const u8, @ptrCast(buffer_view.buffer.data)) +
accessor.offset + buffer_view.offset;

if (accessor.stride == 1) {
if (accessor.component_type != .r_8u) {
return error.InvalidIndicesAccessorComponentType;
}
const src = @as([*]const u8, @ptrCast(data_addr));
var i: u32 = 0;
while (i < num_indices) : (i += 1) {
indices.appendAssumeCapacity(src[i]);
}
} else if (accessor.stride == 2) {
if (accessor.component_type != .r_16u) {
return error.InvalidIndicesAccessorComponentType;
}
const src = @as([*]const u16, @ptrCast(@alignCast(data_addr)));
var i: u32 = 0;
while (i < num_indices) : (i += 1) {
indices.appendAssumeCapacity(src[i]);
}
} else if (accessor.stride == 4) {
if (accessor.component_type != .r_32u) {
return error.InvalidIndicesAccessorComponentType;
}
const src = @as([*]const u32, @ptrCast(@alignCast(data_addr)));
var i: u32 = 0;
while (i < num_indices) : (i += 1) {
indices.appendAssumeCapacity(src[i]);
}
} else {
return error.InvalidIndicesAccessorStride;
}
}

// Attributes.
{
const attributes = prim.attributes[0..prim.attributes_count];
for (attributes) |attrib| {
const accessor = attrib.data;
assert(accessor.component_type == .r_32f);

const buffer_view = accessor.buffer_view.?;
assert(buffer_view.buffer.data != null);

assert(accessor.stride == buffer_view.stride or buffer_view.stride == 0);
assert(accessor.stride * accessor.count == buffer_view.size);

const data_addr = @as([*]const u8, @ptrCast(buffer_view.buffer.data)) +
accessor.offset + buffer_view.offset;

if (attrib.type == .position) {
assert(accessor.type == .vec3);
const slice = @as([*]const [3]f32, @ptrCast(@alignCast(data_addr)))[0..num_vertices];
try positions.appendSlice(slice);
} else if (attrib.type == .normal) {
if (normals) |n| {
assert(accessor.type == .vec3);
const slice = @as([*]const [3]f32, @ptrCast(@alignCast(data_addr)))[0..num_vertices];
try n.appendSlice(slice);
}
} else if (attrib.type == .texcoord) {
if (texcoords0) |tc| {
assert(accessor.type == .vec2);
const slice = @as([*]const [2]f32, @ptrCast(@alignCast(data_addr)))[0..num_vertices];
try tc.appendSlice(slice);
}
} else if (attrib.type == .tangent) {
if (tangents) |tan| {
assert(accessor.type == .vec4);
const slice = @as([*]const [4]f32, @ptrCast(@alignCast(data_addr)))[0..num_vertices];
try tan.appendSlice(slice);
}
}
}
}
}
};
pub const zcgltf = @import("zcgltf.zig");
58 changes: 34 additions & 24 deletions src/memory.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const std = @import("std");
const options = @import("zmesh_options");

pub fn init(alloc: std.mem.Allocator) void {
std.debug.assert(mem_allocator == null and mem_allocations == null);
Expand All @@ -7,10 +8,27 @@ pub fn init(alloc: std.mem.Allocator) void {
mem_allocations = std.AutoHashMap(usize, usize).init(alloc);
mem_allocations.?.ensureTotalCapacity(32) catch unreachable;

zmeshMallocPtr = zmeshMalloc;
zmeshCallocPtr = zmeshCalloc;
zmeshReallocPtr = zmeshRealloc;
zmeshFreePtr = zmeshFree;
const zmeshMallocPtr = @extern(*?*const fn (size: usize) callconv(.c) ?*anyopaque, .{
.name = "zmeshMallocPtr",
.is_dll_import = options.shared,
});
const zmeshCallocPtr = @extern(*?*const fn (num: usize, size: usize) callconv(.c) ?*anyopaque, .{
.name = "zmeshCallocPtr",
.is_dll_import = options.shared,
});
const zmeshReallocPtr = @extern(*?*const fn (ptr: ?*anyopaque, size: usize) callconv(.c) ?*anyopaque, .{
.name = "zmeshReallocPtr",
.is_dll_import = options.shared,
});
const zmeshFreePtr = @extern(*?*const fn (maybe_ptr: ?*anyopaque) callconv(.c) void, .{
.name = "zmeshFreePtr",
.is_dll_import = options.shared,
});

zmeshMallocPtr.* = zmeshMalloc;
zmeshCallocPtr.* = zmeshCalloc;
zmeshReallocPtr.* = zmeshRealloc;
zmeshFreePtr.* = zmeshFree;
meshopt_setAllocator(zmeshMalloc, zmeshFree);
}

Expand All @@ -20,8 +38,8 @@ pub fn deinit() void {
mem_allocator = null;
}

const MallocFn = *const fn (size: usize) callconv(.C) ?*anyopaque;
const FreeFn = *const fn (ptr: ?*anyopaque) callconv(.C) void;
const MallocFn = *const fn (size: usize) callconv(.c) ?*anyopaque;
const FreeFn = *const fn (ptr: ?*anyopaque) callconv(.c) void;

extern fn meshopt_setAllocator(
allocate: MallocFn,
Expand All @@ -31,11 +49,9 @@ extern fn meshopt_setAllocator(
var mem_allocator: ?std.mem.Allocator = null;
var mem_allocations: ?std.AutoHashMap(usize, usize) = null;
var mem_mutex: std.Thread.Mutex = .{};
const mem_alignment = 16;
const mem_alignment: std.mem.Alignment = .@"16";

extern var zmeshMallocPtr: ?*const fn (size: usize) callconv(.C) ?*anyopaque;

pub fn zmeshMalloc(size: usize) callconv(.C) ?*anyopaque {
pub fn zmeshMalloc(size: usize) callconv(.c) ?*anyopaque {
mem_mutex.lock();
defer mem_mutex.unlock();

Expand All @@ -50,9 +66,7 @@ pub fn zmeshMalloc(size: usize) callconv(.C) ?*anyopaque {
return mem.ptr;
}

extern var zmeshCallocPtr: ?*const fn (num: usize, size: usize) callconv(.C) ?*anyopaque;

fn zmeshCalloc(num: usize, size: usize) callconv(.C) ?*anyopaque {
fn zmeshCalloc(num: usize, size: usize) callconv(.c) ?*anyopaque {
const ptr = zmeshMalloc(num * size);
if (ptr != null) {
@memset(@as([*]u8, @ptrCast(ptr))[0 .. num * size], 0);
Expand All @@ -61,23 +75,21 @@ fn zmeshCalloc(num: usize, size: usize) callconv(.C) ?*anyopaque {
return null;
}

pub fn zmeshAllocUser(user: ?*anyopaque, size: usize) callconv(.C) ?*anyopaque {
pub fn zmeshAllocUser(user: ?*anyopaque, size: usize) callconv(.c) ?*anyopaque {
_ = user;
return zmeshMalloc(size);
}

extern var zmeshReallocPtr: ?*const fn (ptr: ?*anyopaque, size: usize) callconv(.C) ?*anyopaque;

fn zmeshRealloc(ptr: ?*anyopaque, size: usize) callconv(.C) ?*anyopaque {
fn zmeshRealloc(ptr: ?*anyopaque, size: usize) callconv(.c) ?*anyopaque {
mem_mutex.lock();
defer mem_mutex.unlock();

const old_size = if (ptr != null) mem_allocations.?.get(@intFromPtr(ptr.?)).? else 0;

const old_mem = if (old_size > 0)
@as([*]align(mem_alignment) u8, @ptrCast(@alignCast(ptr)))[0..old_size]
@as([*]align(mem_alignment.toByteUnits()) u8, @ptrCast(@alignCast(ptr)))[0..old_size]
else
@as([*]align(mem_alignment) u8, undefined)[0..0];
@as([*]align(mem_alignment.toByteUnits()) u8, undefined)[0..0];

const mem = mem_allocator.?.realloc(old_mem, size) catch @panic("zmesh: out of memory");

Expand All @@ -91,20 +103,18 @@ fn zmeshRealloc(ptr: ?*anyopaque, size: usize) callconv(.C) ?*anyopaque {
return mem.ptr;
}

extern var zmeshFreePtr: ?*const fn (maybe_ptr: ?*anyopaque) callconv(.C) void;

fn zmeshFree(maybe_ptr: ?*anyopaque) callconv(.C) void {
fn zmeshFree(maybe_ptr: ?*anyopaque) callconv(.c) void {
if (maybe_ptr) |ptr| {
mem_mutex.lock();
defer mem_mutex.unlock();

const size = mem_allocations.?.fetchRemove(@intFromPtr(ptr)).?.value;
const mem = @as([*]align(mem_alignment) u8, @ptrCast(@alignCast(ptr)))[0..size];
const mem = @as([*]align(mem_alignment.toByteUnits()) u8, @ptrCast(@alignCast(ptr)))[0..size];
mem_allocator.?.free(mem);
}
}

pub fn zmeshFreeUser(user: ?*anyopaque, ptr: ?*anyopaque) callconv(.C) void {
pub fn zmeshFreeUser(user: ?*anyopaque, ptr: ?*anyopaque) callconv(.c) void {
_ = user;
zmeshFree(ptr);
}
Loading
Loading