zgltf upgrade

This commit is contained in:
peterino2 2025-10-13 21:30:07 -07:00
parent d738dd2260
commit 385dccd666
6 changed files with 132 additions and 1686 deletions

View File

@ -1,3 +1,4 @@
.zig-cache/
build_runner.zig
.DS_Store
zig-out

18
lib/zgltf/README.md vendored
View File

@ -9,11 +9,13 @@ Note: It's not as complete as the glTF specification yet, but because it's strai
If you would like to contribute, don't hesitate! :)
Note: The main branch is for the latest Zig release (0.15.1).
## Examples
```zig
const std = @import("std");
const Gltf = @import("zgltf");
const Gltf = @import("zgltf").Gltf;
const allocator = std.heap.page_allocator;
const print = std.debug.print;
@ -29,7 +31,7 @@ pub fn main() void {
);
defer allocator.free(buf);
var gltf = Self.init(allocator);
var gltf = Gltf.init(allocator);
defer gltf.deinit();
try gltf.parse(buf);
@ -42,7 +44,7 @@ pub fn main() void {
;
print(message, .{
node.name,
node.name orelse "Unnamed Node",
node.children.items.len,
node.skin != null,
});
@ -122,11 +124,15 @@ for (primitive.attributes.items) |attribute| {
## Install
Note: **Zig 0.11.x is required.**
Note: **Zig 0.15.1 is required.**
```sh
zig fetch --save git+https://github.com/kooparse/zgltf
```
```zig
const zgltf = @import("path-to-zgltf/build.zig");
exe.addModule("zgltf", zgltf.module(b));
const zgltf = b.dependency("zgltf", .{});
exe.addModule("zgltf", zgltf.module("zgltf"));
```
## Features

19
lib/zgltf/build.zig vendored
View File

@ -3,19 +3,20 @@ const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
_ = static_build;
_ = b.addModule("zgltf", .{
.root_source_file = b.path("src/main.zig"),
});
var tests = b.addTest(.{
.root_source_file = b.path("src/main.zig"),
const mod = b.addModule("zgltf", .{
.root_source_file = b.path("src/zgltf.zig"),
.target = target,
.optimize = optimize,
});
const tests = b.addTest(.{
.root_module = mod,
});
b.installArtifact(tests);
var run_tests = b.addRunArtifact(tests);
const test_step = b.step("test", "Run tests");
test_step.dependOn(&tests.step);
test_step.dependOn(&run_tests.step);
}

View File

@ -1,9 +1,12 @@
.{
.name = .zgltf,
.version = "0.1.0",
.minimum_zig_version = "0.11.0",
.fingerprint = 0x7dfe8a1202907eb1,
.minimum_zig_version = "0.15.1",
.dependencies = .{},
.paths = .{
".github",
".gitignore",
"build.zig",
"build.zig.zon",
"src",
@ -11,5 +14,4 @@
"LICENSE",
"README.md",
},
.fingerprint = 0x7dfe8a12f6d6c124,
}

1612
lib/zgltf/src/main.zig vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
const std = @import("std");
const Gltf = @import("main.zig");
const Gltf = @import("Gltf.zig");
const pi = std.math.pi;
const ArrayList = std.ArrayList;
const panic = std.debug.panic;
const json = @import("std").json;
/// Index of element in data arrays.
pub const Index = usize;
@ -20,8 +20,7 @@ pub const Index = usize;
/// an animation.channel.target), matrix must not be present.
pub const Node = struct {
/// The user-defined name of this object.
/// Default to `Node_{index}`.
name: []const u8,
name: ?[]const u8 = null,
/// The index of the node's parent.
/// A node is called a root node when it doesnt have a parent.
parent: ?Index = null,
@ -32,7 +31,7 @@ pub const Node = struct {
/// The index of the skin referenced by this node.
skin: ?Index = null,
/// The indices of this nodes children.
children: ArrayList(Index),
children: []Index = &[_]Index{},
/// A floating-point 4x4 transformation matrix stored in column-major order.
matrix: ?[16]f32 = null,
/// The nodes unit quaternion rotation in the order (x, y, z, w),
@ -49,6 +48,8 @@ pub const Node = struct {
weights: ?[]usize = null,
///The index of the light referenced by this node.
light: ?Index = null,
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// A buffer points to binary geometry, animation, or skins.
@ -59,6 +60,8 @@ pub const Buffer = struct {
uri: ?[]const u8 = null,
/// The length of the buffer in bytes.
byte_length: usize,
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// A view into a buffer generally representing a subset of the buffer.
@ -74,6 +77,8 @@ pub const BufferView = struct {
/// The hint representing the intended GPU buffer type
/// to use with this buffer view.
target: ?Target = null,
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// A typed view into a buffer view that contains raw binary data.
@ -86,12 +91,12 @@ pub const Accessor = struct {
component_type: ComponentType,
/// Specifies if the accessors elements are scalars, vectors, or matrices.
type: AccessorType,
/// Computed stride: @sizeOf(component_type) * type.
stride: usize,
/// The number of elements referenced by this accessor.
count: i32,
count: usize,
/// Specifies whether integer data values are normalized before usage.
normalized: bool = false,
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
pub fn iterator(
accessor: Accessor,
@ -99,14 +104,7 @@ pub const Accessor = struct {
gltf: *const Gltf,
binary: []align(4) const u8,
) AccessorIterator(T) {
if (switch (accessor.component_type) {
.byte => T != i8,
.unsigned_byte => T != u8,
.short => T != i16,
.unsigned_short => T != u16,
.unsigned_integer => T != u32,
.float => T != f32,
}) {
if (ComponentType.fromType(T) != accessor.component_type) {
panic(
"Mismatch between gltf component '{}' and given type '{}'.",
.{ accessor.component_type, T },
@ -117,30 +115,14 @@ pub const Accessor = struct {
panic("Accessors without buffer_view are not supported yet.", .{});
}
const buffer_view = gltf.data.buffer_views.items[accessor.buffer_view.?];
const buffer_view = gltf.data.buffer_views[accessor.buffer_view.?];
const comp_size = @sizeOf(T);
const offset = (accessor.byte_offset + buffer_view.byte_offset) / comp_size;
const stride = blk: {
if (buffer_view.byte_stride) |byte_stride| {
break :blk byte_stride / comp_size;
} else {
break :blk accessor.stride / comp_size;
}
};
const offset = (accessor.byte_offset + buffer_view.byte_offset) / @sizeOf(T);
const datum_count: usize = accessor.type.componentCount();
// When byte_stride is null, data is tightly packed, so stride = datum_count
const stride = if (buffer_view.byte_stride) |byte_stride| (byte_stride / @sizeOf(T)) else datum_count;
const total_count: usize = @intCast(accessor.count);
const datum_count: usize = switch (accessor.type) {
.scalar => 1,
.vec2 => 2,
.vec3 => 3,
.vec4 => 4,
.mat4x4 => 16,
else => {
panic("Accessor type '{}' not implemented.", .{accessor.type});
},
};
const data: [*]const T = @ptrCast(@alignCast(binary.ptr));
@ -191,22 +173,26 @@ pub fn AccessorIterator(comptime T: type) type {
/// The root nodes of a scene.
pub const Scene = struct {
/// The user-defined name of this object.
name: []const u8,
name: ?[]const u8 = null,
/// The indices of each root node.
nodes: ?ArrayList(Index) = null,
nodes: ?[]Index = null,
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// Joints and matrices defining a skin.
pub const Skin = struct {
/// The user-defined name of this object.
name: []const u8,
name: ?[]const u8 = null,
/// The index of the accessor containing the floating-point
/// 4x4 inverse-bind matrices.
inverse_bind_matrices: ?Index = null,
/// The index of the node used as a skeleton root.
skeleton: ?Index = null,
/// Indices of skeleton nodes, used as joints in this skin.
joints: ArrayList(Index),
joints: []Index = &[_]Index{},
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// Reference to a texture.
@ -260,7 +246,7 @@ pub const MetallicRoughness = struct {
/// The material appearance of a primitive.
pub const Material = struct {
/// The user-defined name of this object.
name: []const u8,
name: ?[]const u8 = null,
/// A set of parameter values that are used to define
/// the metallic-roughness material model
/// from Physically Based Rendering methodology.
@ -309,11 +295,13 @@ pub const Material = struct {
/// The strength of the dispersion effect.
/// Note: from khr_materials_dispersion extension.
dispersion: f32 = 0.0,
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// The materials alpha rendering mode enumeration specifying
/// the interpretation of the alpha value of the base color.
const AlphaMode = enum {
pub const AlphaMode = enum {
/// The alpha value is ignored, and the rendered output is fully opaque.
@"opaque",
/// The rendered output is either fully opaque or fully transparent
@ -337,11 +325,22 @@ pub const Texture = struct {
/// When undefined, an extension or other mechanism should supply
/// an alternate texture source, otherwise behavior is undefined.
source: ?Index = null,
/// Extension object with extension-specific objects.
extensions: struct {
EXT_texture_webp: ?struct {
/// The index of the WebP image used by this texture.
source: Index,
} = null,
} = .{},
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// Image data used to create a texture.
/// Image may be referenced by an uri or a buffer view index.
pub const Image = struct {
/// The user-defined name of this object.
name: ?[]const u8 = null,
/// The URI (or IRI) of the image.
uri: ?[]const u8 = null,
/// The images media type.
@ -353,6 +352,8 @@ pub const Image = struct {
/// The image's data calculated from the buffer/buffer_view.
/// Only there if glb file is loaded.
data: ?[]const u8 = null,
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
pub const WrapMode = enum(u32) {
@ -385,6 +386,8 @@ pub const TextureSampler = struct {
wrap_s: WrapMode = .repeat,
/// T (U) wrapping mode.
wrap_t: WrapMode = .repeat,
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// Values are Accessor's index.
@ -406,6 +409,18 @@ pub const AccessorType = enum {
mat2x2,
mat3x3,
mat4x4,
pub fn componentCount(self: AccessorType) usize {
return switch (self) {
.scalar => 1,
.vec2 => 2,
.vec3 => 3,
.vec4 => 4,
.mat2x2 => 4,
.mat3x3 => 9,
.mat4x4 => 16,
};
}
};
/// Enum values from GLTF 2.0 spec.
@ -416,18 +431,35 @@ pub const Target = enum(u32) {
/// Enum values from GLTF 2.0 spec.
pub const ComponentType = enum(u32) {
/// i8.
byte = 5120,
/// u8.
unsigned_byte = 5121,
/// i16.
short = 5122,
/// u16.
unsigned_short = 5123,
/// u32.
unsigned_integer = 5125,
/// f32.
float = 5126,
pub fn fromType(T: type) ComponentType {
return switch (T) {
i8 => .byte,
u8 => .unsigned_byte,
i16 => .short,
u16 => .unsigned_short,
u32 => .unsigned_integer,
f32 => .float,
else => @compileError("invalid type " ++ @typeName(T) ++ " for ComponentType.fromType"),
};
}
pub fn byteSize(self: ComponentType) usize {
return switch (self) {
.byte => @sizeOf(i8),
.unsigned_byte => @sizeOf(u8),
.short => @sizeOf(i16),
.unsigned_short => @sizeOf(u16),
.unsigned_integer => @sizeOf(u32),
.float => @sizeOf(f32),
};
}
};
/// The topology type of primitives to render.
@ -471,6 +503,8 @@ pub const Channel = struct {
/// of the Morph Targets it instantiates.
property: TargetProperty,
},
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// Interpolation algorithm.
@ -496,41 +530,49 @@ pub const AnimationSampler = struct {
output: Index,
/// Interpolation algorithm.
interpolation: Interpolation = .linear,
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// A keyframe animation.
pub const Animation = struct {
/// The user-defined name of this object.
name: []const u8,
name: ?[]const u8 = null,
/// An array of animation channels.
/// An animation channel combines an animation sampler with a target
/// property being animated.
/// Different channels of the same animation must not have the same targets.
channels: ArrayList(Channel),
channels: []Channel = &[_]Channel{},
/// An array of animation samplers.
/// An animation sampler combines timestamps with a sequence of output
/// values and defines an interpolation algorithm.
samplers: ArrayList(AnimationSampler),
samplers: []AnimationSampler = &[_]AnimationSampler{},
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// Geometry to be rendered with the given material.
pub const Primitive = struct {
attributes: ArrayList(Attribute),
attributes: []Attribute = &[_]Attribute{},
/// The topology type of primitives to render.
mode: Mode = .triangles,
/// The index of the accessor that contains the vertex indices.
indices: ?Index = null,
/// The index of the material to apply to this primitive when rendering.
material: ?Index = null,
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// A set of primitives to be rendered.
/// Its global transform is defined by a node that references it.
pub const Mesh = struct {
/// The user-defined name of this object.
name: []const u8,
name: ?[]const u8 = null,
/// An array of primitives, each defining geometry to be rendered.
primitives: ArrayList(Primitive),
primitives: []Primitive = &[_]Primitive{},
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// Metadata about the glTF asset.
@ -541,6 +583,8 @@ pub const Asset = struct {
generator: ?[]const u8 = null,
/// A copyright message suitable for display to credit the content creator.
copyright: ?[]const u8 = null,
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// A cameras projection.
@ -580,11 +624,13 @@ pub const Camera = struct {
znear: f32,
};
name: []const u8,
name: ?[]const u8 = null,
type: union(enum) {
perspective: Perspective,
orthographic: Orthographic,
},
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
/// Specifies the light type.
@ -614,7 +660,7 @@ pub const LightType = enum {
/// A directional, point or spot light.
pub const Light = struct {
name: ?[]const u8,
name: ?[]const u8 = null,
/// Color of the light source.
color: [3]f32 = .{ 1, 1, 1 },
/// Intensity of the light source. `point` and `spot` lights use luminous intensity in candela (lm/sr)
@ -626,6 +672,8 @@ pub const Light = struct {
spot: ?LightSpot,
/// A distance cutoff at which the light's intensity may be considered to have reached zero.
range: f32,
/// Any extra, custom attributes.
extras: ?json.ObjectMap = null,
};
pub const LightSpot = struct {