The shader compilation story kicks ass now

This commit is contained in:
Peter Li 2025-04-13 18:13:45 -07:00
parent 806c7942e8
commit 341e69b32e
32 changed files with 3529 additions and 94 deletions

View File

@ -21,6 +21,7 @@ const engineDepList = [_][]const u8{
"core",
"papyrus",
"platform",
"rend",
"physics",
};

View File

@ -8,6 +8,7 @@
.papyrus = .{ .path = "engine/papyrus" },
.physics = .{ .path = "engine/physics" },
.platform = .{ .path = "engine/platform" },
.rend = .{.path = "engine/rend" },
.SpirvReflect = .{ .path = "lib/spirv-reflect-zig" },
.ozz = .{ .path = "lib/ozz" },
},

View File

@ -1,6 +1,7 @@
pub const core = @import("core");
pub const platform = @import("platform");
pub const assets = @import("assets");
pub const rend = @import("rend");
pub const audio = @import("audio");
// pub const graphics = @import("graphics");
// pub const vkImgui = @import("vkImgui");

View File

@ -4,6 +4,8 @@ pub const list = [_][]const u8{
"assets",
"audio",
"physics",
"rend",
// to be implemented
// "graphics",
// "ui",

View File

@ -53,9 +53,8 @@ pub const PhysicsCharacter = struct {
const scene = self.entity.get(core.Scene).?;
const p = self.character.getPosition();
const position = .{ .x = p[0], .y = p[1], .z = p[2] };
// core.debugSphere(position, 20, .{});
scene.setPosition(position);
scene.setPosition(.{ .x = p[0], .y = p[1], .z = p[2] });
}
pub fn setVelocity(self: *@This(), v: core.Vectorf) void {

View File

@ -1,14 +1,6 @@
const std = @import("std");
const sdl3 = @import("sdl3");
// pub fn addLib(b: *std.Build, exe: *std.Build.Step.Compile, comptime packagePath: []const u8, cflags: []const []const u8) void {
// _ = b;
// _ = cflags;
//
// exe.addIncludePath(.{ .path = packagePath ++ "/lib" });
// exe.addLibraryPath(.{ .path = packagePath ++ "/lib" });
// }
const dependencyList = [_][]const u8{
"core",
"sdl3",
@ -18,12 +10,6 @@ pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// oh that is interesting. what I can do is have two
// different modules specified here.
//
// one module for each graphics backend
//
// todo,
const mod = b.addModule("platform", .{
.target = target,
.optimize = optimize,

47
engine/rend/build.zig Normal file
View File

@ -0,0 +1,47 @@
const std = @import("std");
const sdl3 = @import("sdl3");
const dependencyList = [_][]const u8{
"core",
"sdl3",
"platform",
"shaderTypes",
"objLoader",
"ozz",
};
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const mod = b.addModule("rend", .{
.target = target,
.optimize = optimize,
.root_source_file = b.path("src/rend.zig"),
});
for (dependencyList) |depName| {
const dep = b.dependency(depName, .{ .target = target, .optimize = optimize });
const dep_mod = dep.module(depName);
mod.addImport(depName, dep_mod);
if (std.mem.eql(u8, depName, "ozz")) {
mod.linkLibrary(dep.artifact("ozz_cpp"));
}
}
sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "sample.vert", b.path("shaders/sample.vert.json"));
// ========== tests ==========
const tests = b.addTest(.{
.target = target,
.optimize = optimize,
.root_source_file = b.path("tests/tests.zig"),
});
const test_step = b.step("test", "run unit tests for rend");
tests.root_module.addImport("platform", mod);
const runArtifact = b.addRunArtifact(tests);
test_step.dependOn(&runArtifact.step);
b.installArtifact(tests);
}

19
engine/rend/build.zig.zon Normal file
View File

@ -0,0 +1,19 @@
.{
.name = .rend,
.version = "0.0.0",
.dependencies = .{
.core = .{ .path = "../core" },
.assets = .{ .path = "../assets" },
.platform = .{ .path = "../platform" },
.sdl3 = .{ .path = "../../lib/sdl3" },
.ozz = .{ .path = "../../lib/ozz" },
.shaderTypes = .{ .path = "../../lib/sdl3/shaderTypes" },
.cgltf = .{ .path = "../../lib/cgltf" },
.objLoader = .{ .path = "../../lib/objLoader" },
},
.paths = .{
"",
},
.fingerprint = 0x1fcf5da860255f09,
}

24
engine/rend/src/rend.zig Normal file
View File

@ -0,0 +1,24 @@
const std = @import("std");
const core = @import("core");
const sample_vert = @import("sample.vert");
// controls glfw and general windowing
// graphics depends on this one
pub const Module: core.ModuleDescription = .{
.name = "rend",
.enabledByDefault = true,
};
pub fn start_module(comptime programSpec: anytype, args: anytype, allocator: std.mem.Allocator) !void {
_ = args;
_ = programSpec;
_ = allocator;
core.engine_log("starting up [REND] module...", .{});
core.engine_log("sample_vert.Scene size = {d}", .{@sizeOf(sample_vert.Scene)});
}
pub fn shutdown_module(allocator: std.mem.Allocator) void {
_ = allocator;
core.engine_log("shutting down [REND] module...", .{});
}

View File

@ -0,0 +1 @@
test "this does nothing" {}

12
lib/sdl3/build.zig vendored
View File

@ -24,6 +24,18 @@ pub fn addShaderDefinition(
return module;
}
pub fn shaderDefintion(
b: *std.Build,
module: *std.Build.Module,
comptime sdl3Path: []const u8,
optimize: std.builtin.OptimizeMode,
shaderName: []const u8,
jsonPath: std.Build.LazyPath,
) void {
const mod = addShaderDefinition(b, sdl3Path, optimize, shaderName, jsonPath);
module.addImport(shaderName, mod);
}
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

3
lib/zgltf/.gitignore vendored Normal file
View File

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

21
lib/zgltf/LICENSE vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Alexandre Chêne
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

162
lib/zgltf/README.md vendored Normal file
View File

@ -0,0 +1,162 @@
# glTF parser for Zig codebase
This project is a glTF 2.0 parser written in Zig, aiming to replace the use of some C/C++ libraries. All glTF types are fully documented, so it comes nicely with IDE autocompletion, reducing
back and forth with the [specification](https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html).
This library intends to mimic the glTF file structure in memory. Thereby it's designed around arrays and indexes instead of pointers as you may see in `cgltf` or other libraries. Also, it's the **user's responsibility** to load glTF files and their related binaries in memory.
Note: It's not as complete as the glTF specification yet, but because it's straightforward to add new parsed fields, we'll get new stuff incrementally and on-demand.
If you would like to contribute, don't hesitate! :)
## Examples
```zig
const std = @import("std");
const Gltf = @import("zgltf");
const allocator = std.heap.page_allocator;
const print = std.debug.print;
pub fn main() void {
const buffer = try std.fs.cwd().readFileAllocOptions(
allocator,
"test-samples/rigged_simple/RiggedSimple.gltf",
512_000,
null,
4,
null
);
defer allocator.free(buf);
var gltf = Self.init(allocator);
defer gltf.deinit();
try gltf.parse(buf);
for (gltf.nodes.items) |node| {
const message =
\\\ Node's name: {s}
\\\ Children count: {}
\\\ Have skin: {}
;
print(message, .{
node.name,
node.children.items.len,
node.skin != null,
});
}
// Or use the debufPrint method.
gltf.debugPrint();
}
```
Also you could easily load data from an `Accessor` with `getDataFromBufferView`:
```zig
const gltf = Gltf.init(allocator);
try gltf.parse(my_gltf_buf);
const bin = try std.fs.cwd().readFileAllocOptions(
allocator,
"test-samples/rigged_simple/RiggedSimple0.bin",
5_000_000,
null,
4,
null
);
defer allocator.free(buf);
var vertices = ArrayList(f32).init(allocator);
defer vertices.deinit();
const mesh = gltf.data.meshes.items[0];
for (mesh.primitives.items) |primitive| {
for (primitive.attributes.items) |attribute| {
switch (attribute) {
// Accessor for mesh vertices:
.position => |accessor_index| {
const accessor = gltf.data.accessors.items[accessor_index];
gltf.getDataFromBufferView(f32, &vertices, accessor, bin);
},
else => {}
}
}
}
```
Also, there is an `iterator` method that helps you pull data from accessors:
```zig
// ...
for (primitive.attributes.items) |attribute| {
switch (attribute) {
.position => |idx| {
const accessor = gltf.data.accessors.items[idx];
var it = accessor.iterator(f32, &gltf, gltf.glb_binary.?);
while (it.next()) |v| {
try vertices.append(.{
.pos = .{ v[0], v[1], v[2] },
.normal = .{ 1, 0, 0 },
.color = .{ 1, 1, 1, 1 },
.uv_x = 0,
.uv_y = 0,
});
}
},
.normal => |idx| {
const accessor = gltf.data.accessors.items[idx];
var it = accessor.iterator(f32, &gltf, gltf.glb_binary.?);
var i: u32 = 0;
while (it.next()) |n| : (i += 1) {
vertices.items[initial_vertex + i].normal = .{ n[0], n[1], n[2] };
}
},
else => {},
}
}
```
## Install
Note: **Zig 0.11.x is required.**
```zig
const zgltf = @import("path-to-zgltf/build.zig");
exe.addModule("zgltf", zgltf.module(b));
```
## Features
- [x] glTF 2.0 json file
- [x] Scenes
- [x] Nodes
- [x] Buffers/BufferViews
- [x] Meshes
- [x] Images
- [x] Materials
- [x] Animations
- [x] Skins
- [x] Cameras
- [x] Parse `glb` files
- [ ] Morth targets
- [ ] Extras data
- [ ] glTF writer
Also, we supports some glTF extensions:
- [x] khr_lights_punctual
- [x] khr_materials_emissive_strength
- [x] khr_materials_ior
- [x] khr_materials_transmission
- [x] khr_materials_volume
- [x] khr_materials_dispersion
## Contributing to the project
Dont be shy about shooting any questions you may have. If you are a beginner/junior, dont hesitate, I will always encourage you. Its a safe place here. Also, I would be very happy to receive any kind of pull requests, you will have (at least) some feedback/guidance rapidly.
Behind screens, there are human beings, living any sort of story. So be always kind and respectful, because we all sheer to learn new things.

19
lib/zgltf/build.zig vendored Normal file
View File

@ -0,0 +1,19 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
_ = b.addModule("zgltf", .{
.root_source_file = b.path("src/main.zig"),
});
var tests = b.addTest(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const test_step = b.step("test", "Run tests");
test_step.dependOn(&tests.step);
}

15
lib/zgltf/build.zig.zon vendored Normal file
View File

@ -0,0 +1,15 @@
.{
.name = .zgltf,
.version = "0.1.0",
.minimum_zig_version = "0.11.0",
.dependencies = .{},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
"test-samples",
"LICENSE",
"README.md",
},
.fingerprint = 0x7dfe8a12f6d6c124,
}

99
lib/zgltf/src/helpers.zig vendored Normal file
View File

@ -0,0 +1,99 @@
//
// Mostly taken from `zalgebra`. I didn't wanted to import the all library.
//
pub const Mat4 = [4][4]f32;
pub const Vec3 = [3]f32;
pub const Quat = [4]f32;
pub const identity = Mat4{
.{ 1, 0, 0, 0 },
.{ 0, 1, 0, 0 },
.{ 0, 0, 1, 0 },
.{ 0, 0, 0, 1 },
};
/// Return 4x4 matrix from given all transform components; `translation`, `rotation` and `scale`.
/// The final order is T * R * S.
pub fn recompose(translation: Vec3, rotation: Quat, scale: Vec3) Mat4 {
const t = blk: {
var mat = identity;
mat[3][0] = translation[0];
mat[3][1] = translation[1];
mat[3][2] = translation[2];
break :blk mat;
};
const r = blk: {
var result = identity;
const x = rotation[0];
const y = rotation[1];
const z = rotation[2];
const w = rotation[3];
const xx = x * x;
const yy = y * y;
const zz = z * z;
const xy = x * y;
const xz = x * z;
const yz = y * z;
const wx = w * x;
const wy = w * y;
const wz = w * z;
result[0][0] = 1.0 - 2.0 * (yy + zz);
result[0][1] = 2.0 * (xy + wz);
result[0][2] = 2.0 * (xz - wy);
result[0][3] = 0.0;
result[1][0] = 2.0 * (xy - wz);
result[1][1] = 1.0 - 2.0 * (xx + zz);
result[1][2] = 2.0 * (yz + wx);
result[1][3] = 0.0;
result[2][0] = 2.0 * (xz + wy);
result[2][1] = 2.0 * (yz - wx);
result[2][2] = 1.0 - 2.0 * (xx + yy);
result[2][3] = 0.0;
result[3][0] = 0.0;
result[3][1] = 0.0;
result[3][2] = 0.0;
result[3][3] = 1.0;
break :blk result;
};
const s = blk: {
var mat = identity;
mat[0][0] = scale[0];
mat[1][1] = scale[1];
mat[2][2] = scale[2];
break :blk mat;
};
return mul(t, mul(r, s));
}
/// Matrices' multiplication.
/// Produce a new matrix from given two matrices.
pub fn mul(left: Mat4, right: Mat4) Mat4 {
var result = identity;
for (result, 0..) |_, column| {
for (result[column], 0..) |_, row| {
var sum: f32 = 0;
var left_column: usize = 0;
while (left_column < 4) : (left_column += 1) {
sum += left[left_column][row] * right[column][left_column];
}
result[column][row] = sum;
}
}
return result;
}

1612
lib/zgltf/src/main.zig vendored Normal file

File diff suppressed because it is too large Load Diff

636
lib/zgltf/src/types.zig vendored Normal file
View File

@ -0,0 +1,636 @@
const std = @import("std");
const Gltf = @import("main.zig");
const pi = std.math.pi;
const ArrayList = std.ArrayList;
const panic = std.debug.panic;
/// Index of element in data arrays.
pub const Index = usize;
/// A node in the node hierarchy.
///
/// When the node contains skin, all mesh.primitives must contain
/// JOINTS_0 and WEIGHTS_0 attributes. A node may have either a matrix
/// or any combination of translation/rotation/scale (TRS) properties.
/// TRS properties are converted to matrices and postmultiplied in
/// the T * R * S order to compose the transformation matrix.
/// If none are provided, the transform is the identity.
///
/// When a node is targeted for animation (referenced by
/// 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,
/// The index of the node's parent.
/// A node is called a root node when it doesnt have a parent.
parent: ?Index = null,
/// The index of the mesh in this node.
mesh: ?Index = null,
/// The index of the camera referenced by this node.
camera: ?Index = null,
/// The index of the skin referenced by this node.
skin: ?Index = null,
/// The indices of this nodes children.
children: ArrayList(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),
/// where w is the scalar.
rotation: [4]f32 = [_]f32{ 0, 0, 0, 1 },
/// The nodes non-uniform scale, given as the scaling factors
/// along the x, y, and z axes.
scale: [3]f32 = [_]f32{ 1, 1, 1 },
/// The nodes translation along the x, y, and z axes.
translation: [3]f32 = [_]f32{ 0, 0, 0 },
/// The weights of the instantiated morph target.
/// The number of array elements must match the number of morph targets
/// of the referenced mesh. When defined, mesh mush also be defined.
weights: ?[]usize = null,
///The index of the light referenced by this node.
light: ?Index = null,
};
/// A buffer points to binary geometry, animation, or skins.
pub const Buffer = struct {
/// Relative paths are relative to the current glTF asset.
/// It could contains a data:-URI instead of a path.
/// Note: data-uri isn't implemented in this library.
uri: ?[]const u8 = null,
/// The length of the buffer in bytes.
byte_length: usize,
};
/// A view into a buffer generally representing a subset of the buffer.
pub const BufferView = struct {
/// The index of the buffer.
buffer: Index,
/// The length of the bufferView in bytes.
byte_length: usize,
/// The offset into the buffer in bytes.
byte_offset: usize = 0,
/// The stride, in bytes.
byte_stride: ?usize = null,
/// The hint representing the intended GPU buffer type
/// to use with this buffer view.
target: ?Target = null,
};
/// A typed view into a buffer view that contains raw binary data.
pub const Accessor = struct {
/// The index of the bufferView.
buffer_view: ?Index = null,
/// The offset relative to the start of the buffer view in bytes.
byte_offset: usize = 0,
/// The datatype of the accessors components.
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,
/// Specifies whether integer data values are normalized before usage.
normalized: bool = false,
pub fn iterator(
accessor: Accessor,
comptime T: type,
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,
}) {
panic(
"Mismatch between gltf component '{}' and given type '{}'.",
.{ accessor.component_type, T },
);
}
if (accessor.buffer_view == null) {
panic("Accessors without buffer_view are not supported yet.", .{});
}
const buffer_view = gltf.data.buffer_views.items[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 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));
return .{
.offset = offset,
.stride = stride,
.total_count = total_count,
.datum_count = datum_count,
.data = data,
.current = 0,
};
}
};
/// Iterator over accessor elements
pub fn AccessorIterator(comptime T: type) type {
return struct {
offset: usize,
stride: usize,
total_count: usize,
datum_count: usize,
data: [*]const T,
current: usize,
/// Returns the next element of the accessor, or null if iteration is done.
pub fn next(self: *@This()) ?[]const T {
if (self.current >= self.total_count) return null;
const slice = (self.data + self.offset + self.current * self.stride)[0..self.datum_count];
self.current += 1;
return slice;
}
/// Returns the next element of the accessor, or null if iteration is done. Does not change self.current.
pub fn peek(self: *const @This()) ?[]const T {
var copy = self.*;
return copy.next();
}
/// Resets the iterator to the first element
pub fn reset(self: *@This()) void {
self.current = 0;
}
};
}
/// The root nodes of a scene.
pub const Scene = struct {
/// The user-defined name of this object.
name: []const u8,
/// The indices of each root node.
nodes: ?ArrayList(Index) = null,
};
/// Joints and matrices defining a skin.
pub const Skin = struct {
/// The user-defined name of this object.
name: []const u8,
/// 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),
};
/// Reference to a texture.
const TextureInfo = struct {
/// The index of the texture.
index: Index,
/// The set index of textures TEXCOORD attribute
/// used for texture coordinate mapping.
texcoord: i32 = 0,
};
/// Reference to a normal texture.
const NormalTextureInfo = struct {
/// The index of the texture.
index: Index,
/// The set index of textures TEXCOORD attribute
/// used for texture coordinate mapping.
texcoord: i32 = 0,
/// The scalar parameter applied to each normal
/// vector of the normal texture.
scale: f32 = 1,
};
/// Reference to an occlusion texture.
const OcclusionTextureInfo = struct {
/// The index of the texture.
index: Index,
/// The set index of textures TEXCOORD attribute
/// used for texture coordinate mapping.
texcoord: i32 = 0,
/// A scalar multiplier controlling the amount of occlusion applied.
strength: f32 = 1,
};
/// A set of parameter values that are used to define
/// the metallic-roughness material model
/// from Physically-Based Rendering methodology.
pub const MetallicRoughness = struct {
/// The factors for the base color of the material.
base_color_factor: [4]f32 = [_]f32{ 1, 1, 1, 1 },
/// The base color texture.
base_color_texture: ?TextureInfo = null,
/// The factor for the metalness of the material.
metallic_factor: f32 = 1,
/// The factor for the roughness of the material.
roughness_factor: f32 = 1,
/// The metallic-roughness texture.
metallic_roughness_texture: ?TextureInfo = null,
};
/// The material appearance of a primitive.
pub const Material = struct {
/// The user-defined name of this object.
name: []const u8,
/// A set of parameter values that are used to define
/// the metallic-roughness material model
/// from Physically Based Rendering methodology.
metallic_roughness: MetallicRoughness = .{},
/// The tangent space normal texture.
normal_texture: ?NormalTextureInfo = null,
/// The occlusion texture.
occlusion_texture: ?OcclusionTextureInfo = null,
/// The emissive texture.
emissive_texture: ?TextureInfo = null,
/// The factors for the emissive color of the material.
emissive_factor: [3]f32 = [_]f32{ 0, 0, 0 },
/// The alpha rendering mode of the material.
alpha_mode: AlphaMode = .@"opaque",
/// The alpha cutoff value of the material.
alpha_cutoff: f32 = 0.5,
/// Specifies whether the material is double sided.
/// If it's false, back-face culling is enabled.
/// If it's true, back-face culling is disabled and
/// double sided lighting is enabled.
is_double_sided: bool = false,
/// Emissive strength multiplier for the emissive factor/texture.
/// Note: from khr_materials_emissive_strength extension.
emissive_strength: f32 = 1.0,
/// Index of refraction of material.
/// Note: from khr_materials_ior extension.
ior: f32 = 1.5,
/// The factor for the transmission of the material.
/// Note: from khr_materials_transmission extension.
transmission_factor: f32 = 0.0,
/// The transmission texture.
/// Note: from khr_materials_transmission extension.
transmission_texture: ?TextureInfo = null,
/// The thickness of the volume beneath the surface.
/// Note: from khr_materials_volume extension.
thickness_factor: f32 = 0.0,
/// A texture that defines the thickness, stored in the G channel.
/// Note: from khr_materials_volume extension.
thickness_texture: ?TextureInfo = null,
/// Density of the medium.
/// Note: from khr_materials_volume extension.
attenuation_distance: f32 = std.math.inf(f32),
/// The color that white light turns into due to absorption.
/// Note: from khr_materials_volume extension.
attenuation_color: [3]f32 = [_]f32{ 1, 1, 1 },
/// The strength of the dispersion effect.
/// Note: from khr_materials_dispersion extension.
dispersion: f32 = 0.0,
};
/// The materials alpha rendering mode enumeration specifying
/// the interpretation of the alpha value of the base color.
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
/// depending on the alpha value and the specified alpha_cutoff value.
/// Note: The exact appearance of the edges may be subject to
/// implementation-specific techniques such as Alpha-to-Coverage.
mask,
/// The alpha value is used to composite the source and destination areas.
/// The rendered output is combined with the background using
/// the normal painting operation (i.e. the Porter and Duff over operator).
blend,
};
/// A texture and its sampler.
pub const Texture = struct {
/// The index of the sampler used by this texture.
/// When undefined, a sampler with repeat wrapping and
/// auto filtering should be used.
sampler: ?Index = null,
/// The index of the image used by this texture.
/// When undefined, an extension or other mechanism should supply
/// an alternate texture source, otherwise behavior is undefined.
source: ?Index = 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 URI (or IRI) of the image.
uri: ?[]const u8 = null,
/// The images media type.
/// This field must be defined when bufferView is defined.
mime_type: ?[]const u8 = null,
/// The index of the bufferView that contains the image.
/// Note: This field must not be defined when uri is defined.
buffer_view: ?Index = null,
/// The image's data calculated from the buffer/buffer_view.
/// Only there if glb file is loaded.
data: ?[]const u8 = null,
};
pub const WrapMode = enum(u32) {
clamp_to_edge = 33071,
mirrored_repeat = 33648,
repeat = 10497,
};
pub const MinFilter = enum(u32) {
nearest = 9728,
linear = 9729,
nearest_mipmap_nearest = 9984,
linear_mipmap_nearest = 9985,
nearest_mipmap_linear = 9986,
linear_mipmap_linear = 9987,
};
pub const MagFilter = enum(u32) {
nearest = 9728,
linear = 9729,
};
/// Texture sampler properties for filtering and wrapping modes.
pub const TextureSampler = struct {
/// Magnification filter.
mag_filter: ?MagFilter = null,
/// Minification filter.
min_filter: ?MinFilter = null,
/// S (U) wrapping mode.
wrap_s: WrapMode = .repeat,
/// T (U) wrapping mode.
wrap_t: WrapMode = .repeat,
};
/// Values are Accessor's index.
pub const Attribute = union(enum) {
position: Index,
normal: Index,
tangent: Index,
texcoord: Index,
color: Index,
joints: Index,
weights: Index,
};
pub const AccessorType = enum {
scalar,
vec2,
vec3,
vec4,
mat2x2,
mat3x3,
mat4x4,
};
/// Enum values from GLTF 2.0 spec.
pub const Target = enum(u32) {
array_buffer = 34962,
element_array_buffer = 34963,
};
/// 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,
};
/// The topology type of primitives to render.
pub const Mode = enum(u32) {
points = 0,
lines = 1,
line_loop = 2,
line_strip = 3,
triangles = 4,
triangle_strip = 5,
triangle_fan = 6,
};
/// The name of the nodes TRS property to animate.
pub const TargetProperty = enum {
/// For the "translation" property, the values that are provided by the
/// sampler are the translation along the X, Y, and Z axes.
translation,
/// For the "rotation" property, the values are a quaternion
/// in the order (x, y, z, w), where w is the scalar.
rotation,
/// For the "scale" property, the values are the scaling
/// factors along the X, Y, and Z axes.
scale,
/// The "weights" of the Morph Targets it instantiates.
weights,
};
/// An animation channel combines an animation sampler
/// with a target property being animated.
pub const Channel = struct {
/// The index of a sampler in this animation used to
/// compute the value for the target.
sampler: Index,
/// The descriptor of the animated property.
target: struct {
/// The index of the node to animate.
/// When undefined, the animated object may be defined by an extension.
node: Index,
/// The name of the nodes TRS property to animate, or the "weights"
/// of the Morph Targets it instantiates.
property: TargetProperty,
},
};
/// Interpolation algorithm.
pub const Interpolation = enum {
/// The animated values are linearly interpolated between keyframes.
/// When targeting a rotation, spherical linear interpolation (slerp)
/// should be used to interpolate quaternions.
linear,
/// The animated values remain constant to the output of the first
/// keyframe, until the next keyframe.
step,
/// The animations interpolation is computed using a cubic
/// spline with specified tangents.
cubicspline,
};
/// An animation sampler combines timestamps
/// with a sequence of output values and defines an interpolation algorithm.
pub const AnimationSampler = struct {
/// The index of an accessor containing keyframe timestamps.
input: Index,
/// The index of an accessor, containing keyframe output values.
output: Index,
/// Interpolation algorithm.
interpolation: Interpolation = .linear,
};
/// A keyframe animation.
pub const Animation = struct {
/// The user-defined name of this object.
name: []const u8,
/// 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),
/// An array of animation samplers.
/// An animation sampler combines timestamps with a sequence of output
/// values and defines an interpolation algorithm.
samplers: ArrayList(AnimationSampler),
};
/// Geometry to be rendered with the given material.
pub const Primitive = struct {
attributes: ArrayList(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,
};
/// 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,
/// An array of primitives, each defining geometry to be rendered.
primitives: ArrayList(Primitive),
};
/// Metadata about the glTF asset.
pub const Asset = struct {
/// The glTF version that this asset targets.
version: []const u8,
/// Tool that generated this glTF model. Useful for debugging.
generator: ?[]const u8 = null,
/// A copyright message suitable for display to credit the content creator.
copyright: ?[]const u8 = null,
};
/// A cameras projection.
/// A node may reference a camera to apply a transform to place the camera
/// in the scene.
pub const Camera = struct {
/// A perspective camera containing properties to create a
/// perspective projection matrix.
pub const Perspective = struct {
/// The aspect ratio of the field of view.
aspect_ratio: ?f32,
/// The vertical field of view in radians.
/// This value should be less than π.
yfov: f32,
/// The distance to the far clipping plane.
zfar: ?f32,
/// The distance to the near clipping plane.
znear: f32,
};
/// An orthographic camera containing properties to create an
/// orthographic projection matrix.
pub const Orthographic = struct {
/// The horizontal magnification of the view.
/// This value must not be equal to zero.
/// This value should not be negative.
xmag: f32,
/// The vertical magnification of the view.
/// This value must not be equal to zero.
/// This value should not be negative.
ymag: f32,
/// The distance to the far clipping plane.
/// This value must not be equal to zero.
/// This value must be greater than znear.
zfar: f32,
/// The distance to the near clipping plane.
znear: f32,
};
name: []const u8,
type: union(enum) {
perspective: Perspective,
orthographic: Orthographic,
},
};
/// Specifies the light type.
pub const LightType = enum {
/// Directional lights act as though they are infinitely far away and emit light in the direction of the local -z axis.
/// This light type inherits the orientation of the node that it belongs to; position and scale are ignored
/// except for their effect on the inherited node orientation. Because it is at an infinite distance,
/// the light is not attenuated. Its intensity is defined in lumens per metre squared, or lux (lm/m^2).
directional,
/// Point lights emit light in all directions from their position in space; rotation and scale are ignored except
/// for their effect on the inherited node position.
/// The brightness of the light attenuates in a physically correct manner as distance increases from
/// the light's position (i.e. brightness goes like the inverse square of the distance).
/// Point light intensity is defined in candela, which is lumens per square radian (lm/sr).
point,
/// Spot lights emit light in a cone in the direction of the local -z axis.
/// The angle and falloff of the cone is defined using two numbers, the innerConeAngle and outerConeAngle.
/// As with point lights, the brightness also attenuates in a physically correct manner as distance
/// increases from the light's position (i.e. brightness goes like the inverse square of the distance).
/// Spot light intensity refers to the brightness inside the innerConeAngle (and at the location of the light) and
/// is defined in candela, which is lumens per square radian (lm/sr).
///
/// Engines that don't support two angles for spotlights should use outerConeAngle as the spotlight angle,
/// leaving innerConeAngle to implicitly be 0.
spot,
};
/// A directional, point or spot light.
pub const Light = struct {
name: ?[]const u8,
/// 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)
/// while `directional` lights use illuminance in lux (lm/m^2).
intensity: f32 = 1,
/// Specifies the light type.
type: LightType,
/// When a light's type is spot, the spot property on the light is required.
spot: ?LightSpot,
/// A distance cutoff at which the light's intensity may be considered to have reached zero.
range: f32,
};
pub const LightSpot = struct {
/// Angle in radians from centre of spotlight where falloff begins.
inner_cone_angle: f32 = 0,
/// Angle in radians from centre of spotlight where falloff ends.
outer_cone_angle: f32 = pi / @as(f32, 4),
};

142
lib/zgltf/test-samples/box/Box.gltf vendored Normal file
View File

@ -0,0 +1,142 @@
{
"asset": {
"generator": "COLLADA2GLTF",
"version": "2.0"
},
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"nodes": [
{
"children": [
1
],
"matrix": [
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
-1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0
]
},
{
"mesh": 0
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 1,
"POSITION": 2
},
"indices": 0,
"mode": 4,
"material": 0
}
],
"name": "Mesh"
}
],
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 36,
"max": [
23
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 24,
"max": [
1.0,
1.0,
1.0
],
"min": [
-1.0,
-1.0,
-1.0
],
"type": "VEC3"
},
{
"bufferView": 1,
"byteOffset": 288,
"componentType": 5126,
"count": 24,
"max": [
0.5,
0.5,
0.5
],
"min": [
-0.5,
-0.5,
-0.5
],
"type": "VEC3"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorFactor": [
0.800000011920929,
0.0,
0.0,
1.0
],
"metallicFactor": 0.0
},
"name": "Red"
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 576,
"byteLength": 72,
"target": 34963
},
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 576,
"byteStride": 12,
"target": 34962
}
],
"buffers": [
{
"byteLength": 648,
"uri": "Box0.bin"
}
]
}

BIN
lib/zgltf/test-samples/box/Box0.bin vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,99 @@
{
"scene" : 0,
"scenes" : [
{
"nodes" : [ 0, 1, 2 ]
}
],
"nodes" : [
{
"rotation" : [ -0.383, 0.0, 0.0, 0.92375 ],
"mesh" : 0
},
{
"translation" : [ 0.5, 0.5, 3.0 ],
"camera" : 0
},
{
"translation" : [ 0.5, 0.5, 3.0 ],
"camera" : 1
}
],
"cameras" : [
{
"type": "perspective",
"perspective": {
"aspectRatio": 1.0,
"yfov": 0.7,
"zfar": 100,
"znear": 0.01
}
},
{
"type": "orthographic",
"orthographic": {
"xmag": 1.0,
"ymag": 1.0,
"zfar": 100,
"znear": 0.01
}
}
],
"meshes" : [
{
"primitives" : [ {
"attributes" : {
"POSITION" : 1
},
"indices" : 0
} ]
}
],
"buffers" : [
{
"uri" : "simpleSquare.bin",
"byteLength" : 60
}
],
"bufferViews" : [
{
"buffer" : 0,
"byteOffset" : 0,
"byteLength" : 12,
"target" : 34963
},
{
"buffer" : 0,
"byteOffset" : 12,
"byteLength" : 48,
"target" : 34962
}
],
"accessors" : [
{
"bufferView" : 0,
"byteOffset" : 0,
"componentType" : 5123,
"count" : 6,
"type" : "SCALAR",
"max" : [ 3 ],
"min" : [ 0 ]
},
{
"bufferView" : 1,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 4,
"type" : "VEC3",
"max" : [ 1.0, 1.0, 0.0 ],
"min" : [ 0.0, 0.0, 0.0 ]
}
],
"asset" : {
"version" : "2.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 B

View File

@ -0,0 +1,158 @@
{
"asset" : {
"generator" : "Khronos glTF Blender I/O v1.1.46",
"version" : "2.0"
},
"extensionsUsed" : [
"KHR_lights_punctual"
],
"extensionsRequired" : [
"KHR_lights_punctual"
],
"extensions" : {
"KHR_lights_punctual" : {
"lights" : [
{
"color" : [
1,
1,
1
],
"intensity" : 1000,
"type" : "point",
"name" : "Light"
},
{
"color" : [
1,
1,
1
],
"intensity" : 1000,
"type" : "spot",
"spot": {
"innerConeAngle": 0,
"outerConeAngle": 1
},
"name" : "Light.001"
},
{
"color" : [
1,
1,
1
],
"intensity" : 1000,
"type" : "directional",
"name" : "Light.002"
}
]
}
},
"scene" : 0,
"scenes" : [
{
"name" : "Scene",
"nodes" : [
1,
3,
5
]
}
],
"nodes" : [
{
"extensions" : {
"KHR_lights_punctual" : {
"light" : 0
}
},
"name" : "Light_Orientation",
"rotation" : [
-0.7071067690849304,
0,
0,
0.7071067690849304
]
},
{
"children" : [
0
],
"name" : "Light",
"rotation" : [
0.16907575726509094,
0.7558803558349609,
-0.27217137813568115,
0.570947527885437
],
"translation" : [
4.076245307922363,
5.903861999511719,
-1.0054539442062378
]
},
{
"extensions" : {
"KHR_lights_punctual" : {
"light" : 1
}
},
"name" : "Light.001_Orientation",
"rotation" : [
-0.7071067690849304,
0,
0,
0.7071067690849304
]
},
{
"children" : [
2
],
"name" : "Light.001",
"rotation" : [
0.16907575726509094,
0.7558803558349609,
-0.27217137813568115,
0.570947527885437
],
"translation" : [
-3.9570322036743164,
1.8591556549072266,
-4.55197811126709
]
},
{
"extensions" : {
"KHR_lights_punctual" : {
"light" : 2
}
},
"name" : "Light.002_Orientation",
"rotation" : [
-0.7071067690849304,
0,
0,
0.7071067690849304
]
},
{
"children" : [
4
],
"name" : "Light.002",
"rotation" : [
0.16907575726509094,
0.7558803558349609,
-0.27217137813568115,
0.570947527885437
],
"translation" : [
0.6759738922119141,
1.6738548278808594,
3.1679487228393555
]
}
]
}

View File

@ -0,0 +1,451 @@
{
"asset": {
"generator": "COLLADA2GLTF",
"version": "2.0"
},
"scenes": [
{
"nodes": [
0
]
}
],
"scene": 0,
"nodes": [
{
"children": [
1
],
"matrix": [
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
-1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0
],
"name": "Z_UP"
},
{
"children": [
3,
2
],
"matrix": [
-4.371139894487897e-8,
-1.0,
0.0,
0.0,
1.0,
-4.371139894487897e-8,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0
],
"name": "Armature"
},
{
"mesh": 0,
"skin": 0,
"name": "Cylinder"
},
{
"children": [
4
],
"matrix": [
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
-1.3597299641787689e-7,
-4.1803297996521,
1.0
],
"name": "Bone"
},
{
"translation": [
1.2150299863455948e-11,
0.02797747030854225,
4.187077045440674
],
"rotation": [
-0.0,
0.0002899225219152868,
-0.0,
-0.9999999403953552
],
"name": "Bone.001"
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"JOINTS_0": 1,
"NORMAL": 2,
"POSITION": 3,
"WEIGHTS_0": 4
},
"indices": 0,
"mode": 4,
"material": 0
}
],
"name": "Cylinder"
}
],
"animations": [
{
"channels": [
{
"sampler": 0,
"target": {
"node": 4,
"path": "translation"
}
},
{
"sampler": 1,
"target": {
"node": 4,
"path": "rotation"
}
},
{
"sampler": 2,
"target": {
"node": 4,
"path": "scale"
}
}
],
"samplers": [
{
"input": 5,
"interpolation": "LINEAR",
"output": 6
},
{
"input": 5,
"interpolation": "LINEAR",
"output": 7
},
{
"input": 5,
"interpolation": "LINEAR",
"output": 8
}
]
}
],
"skins": [
{
"inverseBindMatrices": 9,
"skeleton": 3,
"joints": [
3,
4
],
"name": "Armature"
}
],
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 564,
"max": [
159
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5123,
"count": 160,
"max": [
1,
1,
0,
0
],
"min": [
0,
0,
0,
0
],
"type": "VEC4"
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 160,
"max": [
0.9999632239341736,
0.9999632239341736,
1.0
],
"min": [
-0.9999632239341736,
-0.9999632239341736,
-1.0
],
"type": "VEC3"
},
{
"bufferView": 2,
"byteOffset": 1920,
"componentType": 5126,
"count": 160,
"max": [
1.0,
1.0,
4.575077056884766
],
"min": [
-1.0,
-0.9999995827674866,
-4.575077056884766
],
"type": "VEC3"
},
{
"bufferView": 3,
"byteOffset": 0,
"componentType": 5126,
"count": 160,
"max": [
1.0,
0.26139819622039797,
0.0,
0.0
],
"min": [
0.738601803779602,
0.0,
0.0,
0.0
],
"type": "VEC4"
},
{
"bufferView": 4,
"byteOffset": 0,
"componentType": 5126,
"count": 50,
"max": [
2.083333015441895
],
"min": [
0.04166661947965622
],
"type": "SCALAR"
},
{
"bufferView": 5,
"byteOffset": 0,
"componentType": 5126,
"count": 50,
"max": [
-3.4530497493474868e-14,
0.027977529913187028,
4.187077045440674
],
"min": [
-3.047870116013041e-13,
0.027977488934993745,
4.187077045440674
],
"type": "VEC3"
},
{
"bufferView": 6,
"byteOffset": 0,
"componentType": 5126,
"count": 50,
"max": [
0.2953396439552307,
0.0002899225219152868,
4.162090377207717e-12,
-0.9553922414779664
],
"min": [
-4.6566102085421338e-9,
0.0002769898856058717,
-0.00008562587754568085,
-0.9999999403953552
],
"type": "VEC4"
},
{
"bufferView": 5,
"byteOffset": 600,
"componentType": 5126,
"count": 50,
"max": [
1.0000001192092896,
1.0000001192092896,
1.0
],
"min": [
0.9999999403953552,
0.9999998211860656,
0.9999998211860656
],
"type": "VEC3"
},
{
"bufferView": 7,
"byteOffset": 0,
"componentType": 5126,
"count": 2,
"max": [
0.0,
1.0,
0.0,
0.0,
-0.9999998211860656,
0.0,
0.0005798449856229126,
0.0,
0.0005798449856229126,
0.0,
1.0,
0.0,
0.0,
1.3597299641787689e-7,
4.1803297996521,
1.0
],
"min": [
0.0,
1.0,
0.0,
0.0,
-1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.9999998211860656,
0.0,
-0.000003912100055458723,
-0.02797728031873703,
-0.006746708881109953,
1.0
],
"type": "MAT4"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorFactor": [
0.27963539958000185,
0.6399999856948853,
0.21094390749931336,
1.0
],
"metallicFactor": 0.0
},
"emissiveFactor": [
0.0,
0.0,
0.0
],
"name": "Material_001-effect"
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 10008,
"byteLength": 1128,
"target": 34963
},
{
"buffer": 0,
"byteOffset": 8528,
"byteLength": 1280,
"byteStride": 8,
"target": 34962
},
{
"buffer": 0,
"byteOffset": 4688,
"byteLength": 3840,
"byteStride": 12,
"target": 34962
},
{
"buffer": 0,
"byteOffset": 928,
"byteLength": 2560,
"byteStride": 16,
"target": 34962
},
{
"buffer": 0,
"byteOffset": 9808,
"byteLength": 200
},
{
"buffer": 0,
"byteOffset": 3488,
"byteLength": 1200
},
{
"buffer": 0,
"byteOffset": 128,
"byteLength": 800
},
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 128
}
],
"buffers": [
{
"byteLength": 11136,
"uri": "RiggedSimple0.bin"
}
]
}

Binary file not shown.

View File

@ -1,22 +0,0 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "frag"
}
],
"inputs" : [
{
"type" : "vec4",
"name" : "in.var.TEXCOORD0",
"location" : 0
}
],
"outputs" : [
{
"type" : "vec4",
"name" : "out.var.SV_Target0",
"location" : 0
}
]
}

View File

@ -1,54 +0,0 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "vert"
}
],
"types" : {
"_6" : {
"name" : "Scene",
"members" : [
{
"name" : "color",
"type" : "vec3",
"offset" : 0
}
]
},
"_5" : {
"name" : "type.StructuredBuffer.Scene",
"members" : [
{
"name" : "_m0",
"type" : "_6",
"array" : [
0
],
"array_size_is_literal" : [
true
],
"offset" : 0,
"array_stride" : 16
}
]
}
},
"outputs" : [
{
"type" : "vec4",
"name" : "out.var.TEXCOORD0",
"location" : 0
}
],
"ssbos" : [
{
"type" : "_5",
"name" : "test",
"readonly" : true,
"block_size" : 0,
"set" : 0,
"binding" : 0
}
]
}

View File

@ -26,10 +26,11 @@ pub fn deinit(self: *@This()) void {
}
pub fn main() anyerror!void {
// std.debug.print("hello world\n", .{});
try backlog.initializeAndRunStandardProgram(@This(), .{
.name = "Hello World",
.enabledModules = .{
.physics = true,
},
});
}