Skip to content

Commit

Permalink
sparse
Browse files Browse the repository at this point in the history
  • Loading branch information
ousttrue committed Sep 30, 2024
1 parent a89a653 commit 7469ef3
Show file tree
Hide file tree
Showing 12 changed files with 328 additions and 12 deletions.
7 changes: 6 additions & 1 deletion deps/sokol_samples/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,13 @@ const Sample = struct {
pub const samples = [_]Sample{
.{
.name = "minimal",
.root_source_file = "minimal/main.zig",
.root_source_file = "tutorials/minimal/main.zig",
},
.{
.name = "sparse",
.root_source_file = "tutorials/sparse/main.zig",
},
//
.{
.name = "glb",
.root_source_file = "glb/main.zig",
Expand Down
1 change: 0 additions & 1 deletion deps/sokol_samples/glb/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export fn init() void {

fn on_gltf(gltf: std.json.Parsed(zigltf.Gltf), bin:?[]const u8) void {
state.gltf = gltf;
std.debug.print("{s}\n", .{gltf.value});
state.scene.load(gltf, bin) catch |e| {
std.debug.print("{s}\n", .{@errorName(e)});
@panic("Scene.load");
Expand Down
1 change: 1 addition & 0 deletions deps/sokol_samples/sample_framework/Scene.zig
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub fn load(
json: std.json.Parsed(zigltf.Gltf),
bin: ?[]const u8,
) !void {
std.debug.print("{s}\n", .{json.value});
self.gltf = json;
const gltf = json.value;

Expand Down
1 change: 0 additions & 1 deletion deps/sokol_samples/sample_framework/gltf_fetcher.zig
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ export fn fetch_callback(response: [*c]const sokol.fetch.Response) void {
state.status = "parsed";
gltf_task.callback(parsed, glb.bin);
} else |e| {
// std.debug.print("{s}\n", .{glb.json_bytes});
state.status = std.fmt.bufPrintZ(
&state.status_buffer,
"fail to parse: {s}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const std = @import("std");
const sokol = @import("sokol");
const sg = sokol.gfx;

const title = "minimal";
const zigltf = @import("zigltf");
const rowmath = @import("rowmath");
const framework = @import("framework");
Expand Down Expand Up @@ -142,7 +143,7 @@ export fn frame() void {

sokol.debugtext.canvas(sokol.app.widthf() * 0.5, sokol.app.heightf() * 0.5);
sokol.debugtext.pos(0.5, 0.5);
sokol.debugtext.puts("minimal_gltf");
sokol.debugtext.puts(title);

sg.beginPass(.{
.action = state.pass_action,
Expand Down Expand Up @@ -207,7 +208,7 @@ pub fn main() void {
.event_cb = event,
.width = 800,
.height = 600,
.window_title = "rowmath: examples/sokol/camera_simple",
.window_title = title,
.icon = .{ .sokol_default = true },
.logger = .{ .func = sokol.log.func },
});
Expand Down
221 changes: 221 additions & 0 deletions deps/sokol_samples/tutorials/sparse/main.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
const std = @import("std");
const sokol = @import("sokol");
const sg = sokol.gfx;

const title = "sparse";
const zigltf = @import("zigltf");
const rowmath = @import("rowmath");
const framework = @import("framework");
// const utils = @import("utils");
const Scene = framework.Scene;
// const gltf_fetcher = @import("gltf_fetcher.zig");

// https://github.khronos.org/glTF-Tutorials/gltfTutorial/gltfTutorial_003_MinimalGltfFile.html
const minimal_gltf =
\\{
\\ "scenes" : [ {
\\ "nodes" : [ 0 ]
\\ } ],
\\
\\ "nodes" : [ {
\\ "mesh" : 0
\\ } ],
\\
\\ "meshes" : [ {
\\ "primitives" : [ {
\\ "attributes" : {
\\ "POSITION" : 1
\\ },
\\ "indices" : 0
\\ } ]
\\ } ],
\\
\\ "buffers" : [ {
\\ "uri" : "data:application/gltf-buffer;base64,AAAIAAcAAAABAAgAAQAJAAgAAQACAAkAAgAKAAkAAgADAAoAAwALAAoAAwAEAAsABAAMAAsABAAFAAwABQANAAwABQAGAA0AAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAQAAAAAAAAAAAAABAQAAAAAAAAAAAAACAQAAAAAAAAAAAAACgQAAAAAAAAAAAAADAQAAAAAAAAAAAAAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAQAAAgD8AAAAAAABAQAAAgD8AAAAAAACAQAAAgD8AAAAAAACgQAAAgD8AAAAAAADAQAAAgD8AAAAACAAKAAwAAAAAAIA/AAAAQAAAAAAAAEBAAABAQAAAAAAAAKBAAACAQAAAAAA=",
\\ "byteLength" : 284
\\ } ],
\\
\\ "bufferViews" : [ {
\\ "buffer" : 0,
\\ "byteOffset" : 0,
\\ "byteLength" : 72,
\\ "target" : 34963
\\ }, {
\\ "buffer" : 0,
\\ "byteOffset" : 72,
\\ "byteLength" : 168
\\ }, {
\\ "buffer" : 0,
\\ "byteOffset" : 240,
\\ "byteLength" : 6
\\ }, {
\\ "buffer" : 0,
\\ "byteOffset" : 248,
\\ "byteLength" : 36
\\ } ],
\\
\\ "accessors" : [ {
\\ "bufferView" : 0,
\\ "byteOffset" : 0,
\\ "componentType" : 5123,
\\ "count" : 36,
\\ "type" : "SCALAR",
\\ "max" : [ 13 ],
\\ "min" : [ 0 ]
\\ }, {
\\ "bufferView" : 1,
\\ "byteOffset" : 0,
\\ "componentType" : 5126,
\\ "count" : 14,
\\ "type" : "VEC3",
\\ "max" : [ 6.0, 4.0, 0.0 ],
\\ "min" : [ 0.0, 0.0, 0.0 ],
\\ "sparse" : {
\\ "count" : 3,
\\ "indices" : {
\\ "bufferView" : 2,
\\ "byteOffset" : 0,
\\ "componentType" : 5123
\\ },
\\ "values" : {
\\ "bufferView" : 3,
\\ "byteOffset" : 0
\\ }
\\ }
\\ } ],
\\
\\ "asset" : {
\\ "version" : "2.0"
\\ }
\\}
;

const state = struct {
var pass_action = sg.PassAction{};
var input = rowmath.InputState{};
var orbit = rowmath.OrbitCamera{};
var gltf: ?std.json.Parsed(zigltf.Gltf) = null;
var scene = Scene{};
};

export fn init() void {
sg.setup(.{
.environment = sokol.glue.environment(),
.logger = .{ .func = sokol.log.func },
});
sokol.gl.setup(.{
.logger = .{ .func = sokol.log.func },
});

var debugtext_desc = sokol.debugtext.Desc{
.logger = .{ .func = sokol.log.func },
};
debugtext_desc.fonts[0] = sokol.debugtext.fontOric();
sokol.debugtext.setup(debugtext_desc);

state.pass_action.colors[0] = .{
.load_action = .CLEAR,
.clear_value = .{ .r = 0.1, .g = 0.1, .b = 0.1, .a = 1.0 },
};

state.scene.init(std.heap.c_allocator);

// parse gltf
const allocator = std.heap.c_allocator;
const parsed = std.json.parseFromSlice(
zigltf.Gltf,
allocator,
minimal_gltf,
.{
.ignore_unknown_fields = true,
},
) catch |e| {
std.debug.print("{s}\n", .{@errorName(e)});
@panic("parseFromSlice");
};

// build
state.scene.load(parsed, &.{}) catch |e| {
std.debug.print("{s}\n", .{@errorName(e)});
@panic("Scene.load");
};
}

export fn frame() void {
state.input.screen_width = sokol.app.widthf();
state.input.screen_height = sokol.app.heightf();
state.orbit.frame(state.input);
state.input.mouse_wheel = 0;

sokol.debugtext.canvas(sokol.app.widthf() * 0.5, sokol.app.heightf() * 0.5);
sokol.debugtext.pos(0.5, 0.5);
sokol.debugtext.puts(title);

sg.beginPass(.{
.action = state.pass_action,
.swapchain = sokol.glue.swapchain(),
});
state.scene.draw(state.orbit.camera);
sokol.debugtext.draw();
sg.endPass();
sg.commit();
}

export fn event(e: [*c]const sokol.app.Event) void {
switch (e.*.type) {
.MOUSE_DOWN => {
switch (e.*.mouse_button) {
.LEFT => {
state.input.mouse_left = true;
},
.RIGHT => {
state.input.mouse_right = true;
},
.MIDDLE => {
state.input.mouse_middle = true;
},
.INVALID => {},
}
},
.MOUSE_UP => {
switch (e.*.mouse_button) {
.LEFT => {
state.input.mouse_left = false;
},
.RIGHT => {
state.input.mouse_right = false;
},
.MIDDLE => {
state.input.mouse_middle = false;
},
.INVALID => {},
}
},
.MOUSE_MOVE => {
state.input.mouse_x = e.*.mouse_x;
state.input.mouse_y = e.*.mouse_y;
},
.MOUSE_SCROLL => {
state.input.mouse_wheel = e.*.scroll_y;
},
else => {},
}
}

export fn cleanup() void {
sg.shutdown();
}

pub fn main() void {
sokol.app.run(.{
.init_cb = init,
.frame_cb = frame,
.cleanup_cb = cleanup,
.event_cb = event,
.width = 800,
.height = 600,
.window_title = title,
.icon = .{ .sokol_default = true },
.logger = .{ .func = sokol.log.func },
});
}
52 changes: 49 additions & 3 deletions deps/zigltf/src/GltfBuffer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,62 @@ pub fn getImageBytes(self: *@This(), image_index: u32) ![]const u8 {

pub fn getAccessorBytes(self: *@This(), T: type, accessor_index: u32) ![]const T {
const accessor = self.gltf.accessors[accessor_index];
if (@sizeOf(T) == accessor.stride()) {
if (@sizeOf(T) != accessor.stride()) {
return error.AccessorStrideNotEquals;
}

if (accessor.sparse) |sparse| {
if (accessor.bufferView) |bufferView_index| {
const bufferViewBytes = try self.getBufferViewBytes(bufferView_index);
const bytes = bufferViewBytes[accessor.byteOffset .. accessor.byteOffset + accessor.count * accessor.stride()];
const slice: []const T = @alignCast(std.mem.bytesAsSlice(T, bytes));
var buffer = try self.allocator.alloc(T, accessor.count);
std.mem.copyForwards(T, buffer, slice[0..accessor.count]);

switch (sparse.indices.componentType) {
5121 => {
// u8
std.debug.assert(sparse.indices.byteOffset == 0);
const indices = try self.getBufferViewBytes(sparse.indices.bufferView);
std.debug.assert(sparse.values.byteOffset == 0);
const values = try self.getBufferViewBytes(sparse.values.bufferView);
const values_t: []const T = @alignCast(std.mem.bytesAsSlice(T, values));
for (indices, 0..) |index, i| {
buffer[index] = values_t[i];
}
},
5123 => {
// u16
std.debug.assert(sparse.indices.byteOffset == 0);
const indices = try self.getBufferViewBytes(sparse.indices.bufferView);
const indices_t: []const u16 = @alignCast(std.mem.bytesAsSlice(u16, indices));
std.debug.assert(sparse.values.byteOffset == 0);
const values = try self.getBufferViewBytes(sparse.values.bufferView);
const values_t: []const T = @alignCast(std.mem.bytesAsSlice(T, values));
for (indices_t, 0..) |index, i| {
buffer[index] = values_t[i];
}
},
5125 => {
// u32
@panic("u32 sparse indices");
},
else => {
unreachable;
},
}
return buffer;
} else {
@panic("zero sparse not impl");
}
} else {
if (accessor.bufferView) |bufferView_index| {
const bufferViewBytes = try self.getBufferViewBytes(bufferView_index);
const bytes = bufferViewBytes[accessor.byteOffset .. accessor.byteOffset + accessor.count * accessor.stride()];
return @alignCast(std.mem.bytesAsSlice(T, bytes));
} else {
unreachable;
}
} else {
return error.AccessorStrideNotEquals;
}
}

Expand Down
24 changes: 20 additions & 4 deletions deps/zigltf/src/types/Accessor.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const std = @import("std");
const format_helper = @import("format_helper.zig");
pub const AccessorSparse = @import("AccessorSparse.zig");
pub const Accessor = @This();

name: ?[]const u8 = null,
Expand All @@ -8,6 +9,7 @@ type: []const u8,
count: u32,
bufferView: ?u32 = null,
byteOffset: u32 = 0,
sparse: ?AccessorSparse = null,

fn componentTypeToStr(componentType: u32) []const u8 {
return switch (componentType) {
Expand Down Expand Up @@ -57,10 +59,24 @@ pub fn format(
typeToSuffix(self.type),
self.count,
});
if (self.bufferView) |bufferView| {
try writer.print(" => bufferView#{}", .{bufferView});
if (self.byteOffset > 0) {
try writer.print("+{}", .{self.byteOffset});
if (self.sparse) |sparse| {
if (self.bufferView) |bufferView| {
try writer.print(" => bufferView#{} + sparse[{}]", .{
bufferView,
sparse.count,
});
} else {
// the sparse accessor is initialized as an array of zeros of size (size of the accessor element) * (accessor.count) bytes.
try writer.print(" => + sparse[{}]", .{
sparse.count,
});
}
} else {
if (self.bufferView) |bufferView| {
try writer.print(" => bufferView#{}", .{bufferView});
if (self.byteOffset > 0) {
try writer.print("+{}", .{self.byteOffset});
}
}
}
}
Expand Down
Loading

0 comments on commit 7469ef3

Please sign in to comment.