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/ .zig-cache/
build_runner.zig build_runner.zig
.DS_Store .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! :) If you would like to contribute, don't hesitate! :)
Note: The main branch is for the latest Zig release (0.15.1).
## Examples ## Examples
```zig ```zig
const std = @import("std"); const std = @import("std");
const Gltf = @import("zgltf"); const Gltf = @import("zgltf").Gltf;
const allocator = std.heap.page_allocator; const allocator = std.heap.page_allocator;
const print = std.debug.print; const print = std.debug.print;
@ -29,7 +31,7 @@ pub fn main() void {
); );
defer allocator.free(buf); defer allocator.free(buf);
var gltf = Self.init(allocator); var gltf = Gltf.init(allocator);
defer gltf.deinit(); defer gltf.deinit();
try gltf.parse(buf); try gltf.parse(buf);
@ -42,7 +44,7 @@ pub fn main() void {
; ;
print(message, .{ print(message, .{
node.name, node.name orelse "Unnamed Node",
node.children.items.len, node.children.items.len,
node.skin != null, node.skin != null,
}); });
@ -122,11 +124,15 @@ for (primitive.attributes.items) |attribute| {
## Install ## 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 ```zig
const zgltf = @import("path-to-zgltf/build.zig"); const zgltf = b.dependency("zgltf", .{});
exe.addModule("zgltf", zgltf.module(b)); exe.addModule("zgltf", zgltf.module("zgltf"));
``` ```
## Features ## Features

19
lib/zgltf/build.zig vendored
View File

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