Compare commits
2 Commits
inlined
...
feature/in
| Author | SHA1 | Date | |
|---|---|---|---|
| 302f96af3f | |||
| 879e442ac6 |
@@ -7,38 +7,144 @@ const Mesh = @import("mesh.zig");
|
||||
const Shader = @import("shader.zig");
|
||||
const Tree = @import("../tree.zig").Tree;
|
||||
|
||||
pub const Animation = struct {
|
||||
rotation: zm.Quat,
|
||||
translation: zm.Mat,
|
||||
};
|
||||
|
||||
pub const JointData = struct {
|
||||
mesh: Mesh,
|
||||
translation: zm.Mat,
|
||||
rotation: zm.Quat,
|
||||
animated_transform: zm.Mat = zm.identity(),
|
||||
local_bind_transform: zm.Mat,
|
||||
inverse_bind_transform: zm.Mat = zm.identity(),
|
||||
keyframes: [2]Animation,
|
||||
count: usize,
|
||||
|
||||
var counter: usize = 0;
|
||||
|
||||
pub fn init(mesh: Mesh, translation: zm.Mat, rotation: zm.Quat, keyframes: [2]zm.Quat) JointData {
|
||||
const res = JointData{
|
||||
.mesh = mesh,
|
||||
.local_bind_transform = zm.mul(
|
||||
zm.quatToMat(rotation),
|
||||
translation,
|
||||
),
|
||||
.count = counter,
|
||||
.keyframes = .{
|
||||
.{ .rotation = keyframes[0], .translation = translation },
|
||||
.{ .rotation = keyframes[1], .translation = translation },
|
||||
},
|
||||
};
|
||||
counter += 1;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
data: Tree(JointData),
|
||||
animaton_duration: f32 = 1,
|
||||
animaton_time: f32 = 0,
|
||||
|
||||
pub fn init(
|
||||
data: Tree(JointData),
|
||||
) @This() {
|
||||
pub fn init(data: Tree(JointData)) !@This() {
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
const arena_allocator = arena.allocator();
|
||||
|
||||
var c_data = data;
|
||||
|
||||
var iter = try c_data.levelOrderIterator(arena_allocator);
|
||||
|
||||
while (iter.next()) |node| {
|
||||
for (node.children.items) |*child| {
|
||||
child.val.local_bind_transform = zm.mul(
|
||||
child.val.local_bind_transform,
|
||||
node.val.local_bind_transform,
|
||||
);
|
||||
}
|
||||
}
|
||||
return .{ .data = data };
|
||||
}
|
||||
|
||||
pub fn draw(self: *@This(), shader: Shader) void {
|
||||
var iter = self.data.depthFirstIterator();
|
||||
while (iter.next()) |node| {
|
||||
var rotation = node.val.rotation;
|
||||
var current = node;
|
||||
while (current.parent) |parent| {
|
||||
rotation = zm.qmul(rotation, parent.val.rotation);
|
||||
current = parent;
|
||||
}
|
||||
pub fn draw(self: *@This(), shader: Shader) !void {
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
const allocator = arena.allocator();
|
||||
|
||||
const model_matrix = zm.mul(zm.quatToMat(rotation), node.val.translation);
|
||||
const normal_matrix = zm.transpose(zm.inverse(model_matrix));
|
||||
var iter = try self.data.preOrderIterator(allocator);
|
||||
defer iter.deinit(allocator);
|
||||
|
||||
while (iter.next()) |node| {
|
||||
const model_matrix = zm.mul(
|
||||
node.val.animated_transform,
|
||||
node.val.local_bind_transform,
|
||||
);
|
||||
shader.updateUniformMatrix("u_model_matrix", &.{model_matrix});
|
||||
shader.updateUniformMatrix("u_normal_matrix", &.{normal_matrix});
|
||||
shader.updateUniformMatrix("u_normal_matrix", &.{zm.transpose(zm.inverse(model_matrix))});
|
||||
node.val.mesh.draw(shader);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
|
||||
self.data.deinit(allocator);
|
||||
pub fn animate(self: *@This(), delta_time: f32) !void {
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
const arena_allocator = arena.allocator();
|
||||
|
||||
var iter = try self.data.levelOrderIterator(arena_allocator);
|
||||
|
||||
self.animaton_time += delta_time;
|
||||
|
||||
if (self.animaton_time / self.animaton_duration < 1) {
|
||||
while (iter.next()) |node| {
|
||||
node.val.animated_transform = zm.mul(
|
||||
zm.quatToMat(zm.slerp(
|
||||
node.val.keyframes[0].rotation,
|
||||
node.val.keyframes[1].rotation,
|
||||
self.animaton_time / self.animaton_duration,
|
||||
)),
|
||||
node.val.keyframes[0].translation,
|
||||
);
|
||||
|
||||
for (node.children.items) |*child| {
|
||||
child.val.animated_transform = zm.mul(
|
||||
node.val.animated_transform,
|
||||
child.val.animated_transform,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (self.animaton_time / self.animaton_duration < 2) {
|
||||
while (iter.next()) |node| {
|
||||
node.val.animated_transform = zm.mul(
|
||||
zm.quatToMat(zm.slerp(
|
||||
node.val.keyframes[1].rotation,
|
||||
node.val.keyframes[0].rotation,
|
||||
self.animaton_time / self.animaton_duration - 1,
|
||||
)),
|
||||
node.val.keyframes[1].translation,
|
||||
);
|
||||
|
||||
for (node.children.items) |*child| {
|
||||
child.val.animated_transform = zm.mul(
|
||||
child.val.animated_transform,
|
||||
node.val.animated_transform,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.animaton_time = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
iter = try self.data.levelOrderIterator(arena_allocator);
|
||||
|
||||
// while (iter.next()) |node| {
|
||||
// for (node.children.items) |*child| {
|
||||
// child.val.animated_transform = zm.mul(
|
||||
// node.val.animated_transform,
|
||||
// child.val.animated_transform,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn deinit(self: *@This(), allocator: std.mem.Allocator) !void {
|
||||
try self.data.deinit(allocator);
|
||||
}
|
||||
|
||||
318
src/main.zig
318
src/main.zig
@@ -96,37 +96,8 @@ pub fn main() !void {
|
||||
const floor = initFloor(floor_texture);
|
||||
defer floor.delete();
|
||||
|
||||
var shape = Shape.initCube();
|
||||
defer shape.deinit();
|
||||
|
||||
shape.unweld();
|
||||
shape.computeNormals();
|
||||
shape.translate(-0.5, -1, -0.5);
|
||||
|
||||
var chest = shape.clone();
|
||||
defer chest.deinit();
|
||||
chest.scale(0.3, 0.4, 0.15);
|
||||
|
||||
var model_data = Tree(Model.JointData).init(.{
|
||||
.mesh = Mesh.initShape(chest, robot_texture, .triangles),
|
||||
.translation = zm.translation(0, 0.425 + 0.4, 0),
|
||||
.rotation = zm.qidentity(),
|
||||
});
|
||||
|
||||
var head = shape.clone();
|
||||
defer head.deinit();
|
||||
head.scale(0.1, 0.1, 0.1);
|
||||
|
||||
try model_data.root.append(allocator, .{
|
||||
.mesh = Mesh.initShape(head, robot_texture, .triangles),
|
||||
.translation = zm.translation(0, 0.425 + 0.4 + 0.1, 0),
|
||||
.rotation = zm.qidentity(),
|
||||
});
|
||||
|
||||
var robot = Model.init(model_data);
|
||||
|
||||
// var robot = try initRobot(allocator, robot_texture);
|
||||
defer robot.deinit(allocator);
|
||||
var robot = try initRobot(allocator, robot_texture);
|
||||
defer robot.deinit(allocator) catch {};
|
||||
|
||||
// uniform data
|
||||
var light_color = zm.f32x4(1, 1, 1, 1);
|
||||
@@ -162,7 +133,6 @@ pub fn main() !void {
|
||||
var previous_time = glfw_helper.getTime();
|
||||
var current_time: f64 = 0;
|
||||
var delta_time: f64 = undefined;
|
||||
// var frame_counter: u16 = 0;
|
||||
|
||||
// OpenGL setup
|
||||
const clear_color = FloatColor.sky_blue;
|
||||
@@ -191,8 +161,8 @@ pub fn main() !void {
|
||||
model_shader.updateUniformMatrix("u_normal_matrix", &.{zm.identity()});
|
||||
floor.draw(model_shader);
|
||||
|
||||
// animateRobot(&frame_counter, robot);
|
||||
robot.draw(model_shader);
|
||||
try robot.animate(@floatCast(delta_time));
|
||||
try robot.draw(model_shader);
|
||||
},
|
||||
.fish => {},
|
||||
}
|
||||
@@ -233,125 +203,207 @@ fn initFloor(textures: ?[]const Texture) Mesh {
|
||||
}
|
||||
|
||||
fn initRobot(allocator: std.mem.Allocator, textures: ?[]const Texture) !Model {
|
||||
// var meshes = try std.ArrayList(Mesh).initCapacity(allocator, 14);
|
||||
// var translations = try std.ArrayList(Mat).initCapacity(allocator, 14);
|
||||
|
||||
var shape = Shape.initCube();
|
||||
defer shape.deinit();
|
||||
|
||||
shape.unweld();
|
||||
shape.computeNormals();
|
||||
shape.translate(-0.5, -1, -0.5);
|
||||
// shape.rotate(std.math.degreesToRadians(180), 1, 0, 0);
|
||||
|
||||
// var foot = shape.clone();
|
||||
// defer foot.deinit();
|
||||
// foot.scale(0.1, 0.025, 0.15);
|
||||
// meshes.appendNTimesAssumeCapacity(Mesh.initShape(foot, textures, .triangles), 2);
|
||||
// translations.appendAssumeCapacity(zm.translation(-0.07, 0.025, 0));
|
||||
// translations.appendAssumeCapacity(zm.translation(0.07, 0.025, 0));
|
||||
|
||||
// var leg = shape.clone();
|
||||
// defer leg.deinit();
|
||||
// leg.scale(0.08, 0.2, 0.08);
|
||||
// meshes.appendNTimesAssumeCapacity(Mesh.initShape(leg, textures, .triangles), 4);
|
||||
// translations.appendAssumeCapacity(zm.translation(-0.07, 0.225, 0));
|
||||
// translations.appendAssumeCapacity(zm.translation(0.07, 0.225, 0));
|
||||
// translations.appendAssumeCapacity(zm.translation(-0.07, 0.425, 0));
|
||||
// translations.appendAssumeCapacity(zm.translation(0.07, 0.425, 0));
|
||||
|
||||
// var arm = shape.clone();
|
||||
// defer arm.deinit();
|
||||
// arm.scale(0.08, 0.2, 0.08);
|
||||
// meshes.appendNTimesAssumeCapacity(Mesh.initShape(arm, textures, .triangles), 4);
|
||||
// translations.appendAssumeCapacity(zm.translation(-0.3 / 2.0 - 0.04, 0.225 + 0.4, 0));
|
||||
// translations.appendAssumeCapacity(zm.translation(0.3 / 2.0 + 0.04, 0.225 + 0.4, 0));
|
||||
// translations.appendAssumeCapacity(zm.translation(-0.3 / 2.0 - 0.04, 0.425 + 0.4, 0));
|
||||
// translations.appendAssumeCapacity(zm.translation(0.3 / 2.0 + 0.04, 0.425 + 0.4, 0));
|
||||
|
||||
// var hand = shape.clone();
|
||||
// defer hand.deinit();
|
||||
// hand.scale(0.025, 0.08, 0.07);
|
||||
// meshes.appendNTimesAssumeCapacity(Mesh.initShape(hand, textures, .triangles), 2);
|
||||
// translations.appendAssumeCapacity(zm.translation(-0.3 / 2.0 - 0.04, 0.425, 0));
|
||||
// translations.appendAssumeCapacity(zm.translation(0.3 / 2.0 + 0.04, 0.425, 0));
|
||||
|
||||
var chest = shape.clone();
|
||||
defer chest.deinit();
|
||||
chest.scale(0.3, 0.4, 0.15);
|
||||
// meshes.appendAssumeCapacity(Mesh.initShape(chest, textures, .triangles));
|
||||
// translations.appendAssumeCapacity(zm.translation(0, 0.425 + 0.4, 0));
|
||||
|
||||
var model_data = Tree(Model.JointData).init(
|
||||
.{
|
||||
.mesh = Mesh.initShape(chest, textures, .triangles),
|
||||
.translation = zm.translation(0, 0.425 + 0.4, 0),
|
||||
.rotation = zm.qidentity(),
|
||||
},
|
||||
.init(
|
||||
.initShape(chest, textures, .triangles),
|
||||
zm.translation(0, 0.825, 0),
|
||||
zm.qidentity(),
|
||||
.{ zm.qidentity(), zm.qidentity() },
|
||||
),
|
||||
);
|
||||
|
||||
var head = shape.clone();
|
||||
defer head.deinit();
|
||||
head.scale(0.1, 0.1, 0.1);
|
||||
head.rotate(std.math.degreesToRadians(180), 1, 0, 0);
|
||||
try model_data.root.append(
|
||||
allocator,
|
||||
.init(
|
||||
.initShape(head, textures, .triangles),
|
||||
zm.translation(0, 0, 0),
|
||||
zm.qidentity(),
|
||||
.{
|
||||
zm.quatFromRollPitchYaw(0, -0.5, 0),
|
||||
zm.quatFromRollPitchYaw(0, 0.5, 0),
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
try model_data.root.append(allocator, .{
|
||||
.mesh = Mesh.initShape(head, textures, .triangles),
|
||||
.translation = zm.translation(0, 0.425 + 0.4 + 0.1, 0),
|
||||
.rotation = zm.qidentity(),
|
||||
});
|
||||
// meshes.appendAssumeCapacity(Mesh.initShape(head, textures, .triangles));
|
||||
// translations.appendAssumeCapacity(zm.translation(0, 0.425 + 0.4 + 0.1, 0));
|
||||
var arm = shape.clone();
|
||||
defer arm.deinit();
|
||||
arm.scale(0.08, 0.2, 0.08);
|
||||
var right_arm = try model_data.root.create(
|
||||
allocator,
|
||||
.init(
|
||||
.initShape(arm, textures, .triangles),
|
||||
zm.translation(-0.3 / 2.0 - 0.04, 0, 0),
|
||||
zm.qidentity(),
|
||||
.{
|
||||
zm.quatFromRollPitchYaw(0.6, 0, 0),
|
||||
zm.quatFromRollPitchYaw(-0.6, 0, 0),
|
||||
},
|
||||
),
|
||||
);
|
||||
right_arm = try right_arm.create(
|
||||
allocator,
|
||||
.init(
|
||||
.initShape(arm, textures, .triangles),
|
||||
zm.translation(0, -0.2, 0),
|
||||
zm.quatFromRollPitchYaw(-0.6, 0, 0),
|
||||
.{
|
||||
zm.quatFromRollPitchYaw(0.6, 0, 0),
|
||||
zm.quatFromRollPitchYaw(-0.6, 0, 0),
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
return Model.init(model_data);
|
||||
var left_arm = try model_data.root.create(
|
||||
allocator,
|
||||
.init(
|
||||
.initShape(arm, textures, .triangles),
|
||||
zm.translation(0.3 / 2.0 + 0.04, 0, 0),
|
||||
zm.qidentity(),
|
||||
.{
|
||||
zm.qidentity(),
|
||||
zm.qidentity(),
|
||||
},
|
||||
),
|
||||
);
|
||||
left_arm = try left_arm.create(
|
||||
allocator,
|
||||
.init(
|
||||
.initShape(arm, textures, .triangles),
|
||||
zm.translation(0, -0.2, 0),
|
||||
zm.qidentity(),
|
||||
.{
|
||||
zm.qidentity(),
|
||||
zm.qidentity(),
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
var hand = shape.clone();
|
||||
defer hand.deinit();
|
||||
hand.scale(0.025, 0.08, 0.07);
|
||||
try right_arm.append(
|
||||
allocator,
|
||||
.init(
|
||||
.initShape(hand, textures, .triangles),
|
||||
zm.translation(0, -0.2, 0),
|
||||
zm.qidentity(),
|
||||
.{
|
||||
zm.qidentity(),
|
||||
zm.qidentity(),
|
||||
},
|
||||
),
|
||||
);
|
||||
try left_arm.append(
|
||||
allocator,
|
||||
.init(
|
||||
.initShape(hand, textures, .triangles),
|
||||
zm.translation(0, -0.2, 0),
|
||||
zm.qidentity(),
|
||||
.{
|
||||
zm.qidentity(),
|
||||
zm.qidentity(),
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
var leg = shape.clone();
|
||||
defer leg.deinit();
|
||||
leg.scale(0.08, 0.2, 0.08);
|
||||
var right_leg = try model_data.root.create(
|
||||
allocator,
|
||||
.init(
|
||||
.initShape(leg, textures, .triangles),
|
||||
zm.translation(-0.07, -0.4, 0),
|
||||
zm.qidentity(),
|
||||
.{
|
||||
zm.qidentity(),
|
||||
zm.qidentity(),
|
||||
},
|
||||
),
|
||||
);
|
||||
right_leg = try right_leg.create(
|
||||
allocator,
|
||||
.init(
|
||||
.initShape(leg, textures, .triangles),
|
||||
zm.translation(0, -0.2, 0),
|
||||
zm.qidentity(),
|
||||
.{
|
||||
zm.qidentity(),
|
||||
zm.qidentity(),
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
var left_leg = try model_data.root.create(
|
||||
allocator,
|
||||
.init(
|
||||
.initShape(leg, textures, .triangles),
|
||||
zm.translation(0.07, -0.4, 0),
|
||||
zm.qidentity(),
|
||||
.{
|
||||
zm.qidentity(),
|
||||
zm.qidentity(),
|
||||
},
|
||||
),
|
||||
);
|
||||
left_leg = try left_leg.create(
|
||||
allocator,
|
||||
.init(
|
||||
.initShape(leg, textures, .triangles),
|
||||
zm.translation(0, -0.2, 0),
|
||||
zm.qidentity(),
|
||||
.{
|
||||
zm.qidentity(),
|
||||
zm.qidentity(),
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
var foot = shape.clone();
|
||||
defer foot.deinit();
|
||||
foot.scale(0.1, 0.025, 0.15);
|
||||
try right_leg.append(
|
||||
allocator,
|
||||
.init(
|
||||
.initShape(foot, textures, .triangles),
|
||||
zm.translation(0, -0.2, 0),
|
||||
zm.qidentity(),
|
||||
.{
|
||||
zm.qidentity(),
|
||||
zm.qidentity(),
|
||||
},
|
||||
),
|
||||
);
|
||||
try left_leg.append(
|
||||
allocator,
|
||||
.init(
|
||||
.initShape(foot, textures, .triangles),
|
||||
zm.translation(0, -0.2, 0),
|
||||
zm.qidentity(),
|
||||
.{
|
||||
zm.qidentity(),
|
||||
zm.qidentity(),
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
return try Model.init(model_data);
|
||||
}
|
||||
|
||||
// fn initRobot(allocator: std.mem.Allocator, textures: ?[]const Texture) Model {
|
||||
// var shape = Shape.initCube();
|
||||
// defer shape.deinit();
|
||||
|
||||
// shape.unweld();
|
||||
// shape.computeNormals();
|
||||
// shape.translate(-0.5, -1, -0.5);
|
||||
|
||||
// var chest = shape.clone();
|
||||
// defer chest.deinit();
|
||||
// chest.scale(0.3, 0.4, 0.15);
|
||||
|
||||
// var model_data = Tree(Model.JointData).init(.{
|
||||
// .mesh = Mesh.initShape(chest, textures, .triangles),
|
||||
// .translation = zm.translation(0, 0.425 + 0.4, 0),
|
||||
// .rotation = zm.qidentity(),
|
||||
// });
|
||||
|
||||
// var head = shape.clone();
|
||||
// defer head.deinit();
|
||||
// head.scale(0.1, 0.1, 0.1);
|
||||
|
||||
// try model_data.root.append(allocator, .{
|
||||
// .mesh = Mesh.initShape(head, textures, .triangles),
|
||||
// .translation = zm.translation(0, 0.425 + 0.4 + 0.1, 0),
|
||||
// .rotation = zm.qidentity(),
|
||||
// });
|
||||
|
||||
// return Model.init(model_data);
|
||||
// }
|
||||
|
||||
// fn animateRobot(frame_counter: *u16, robot: Model) void {
|
||||
// if (frame_counter.* > robot.animation_frames) {
|
||||
// robot.translations.items[2] = zm.mul(zm.rotationX(-std.math.degreesToRadians(1)), robot.translations.items[2]);
|
||||
// robot.translations.items[3] = zm.mul(zm.rotationX(-std.math.degreesToRadians(1)), robot.translations.items[3]);
|
||||
// } else {
|
||||
// robot.translations.items[2] = zm.mul(zm.rotationX(std.math.degreesToRadians(1)), robot.translations.items[2]);
|
||||
// robot.translations.items[3] = zm.mul(zm.rotationX(std.math.degreesToRadians(1)), robot.translations.items[3]);
|
||||
// }
|
||||
|
||||
// frame_counter.* += 1;
|
||||
|
||||
// if (frame_counter.* > robot.animation_frames * 2) {
|
||||
// frame_counter.* = 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
fn drawGui(light_ubo: zgl.Buffer, light_shader: gl_helper.Shader, light_color: *zm.Vec) void {
|
||||
if (app_state.render_gui) {
|
||||
zgui.backend.newFrame(@intCast(app_state.width), @intCast(app_state.height));
|
||||
|
||||
245
src/tree.zig
245
src/tree.zig
@@ -1,5 +1,6 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
|
||||
pub fn Tree(comptime T: type) type {
|
||||
return struct {
|
||||
@@ -7,91 +8,210 @@ pub fn Tree(comptime T: type) type {
|
||||
|
||||
root: Node,
|
||||
|
||||
const Children = std.ArrayList(Node);
|
||||
const Children = ArrayList(Node);
|
||||
const Node = struct {
|
||||
val: T,
|
||||
parent: ?*Node,
|
||||
index: usize,
|
||||
children: std.ArrayList(Node),
|
||||
children: ArrayList(Node),
|
||||
|
||||
pub fn init(val: T, parent: ?*Node, index: usize) Node {
|
||||
pub fn init(val: T) Node {
|
||||
return .{
|
||||
.val = val,
|
||||
.children = .empty,
|
||||
.parent = parent,
|
||||
.index = index,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn append(self: *Node, allocator: Allocator, val: T) !void {
|
||||
const child = Node.init(val, self, self.children.items.len);
|
||||
const child = Node.init(val);
|
||||
try self.children.append(allocator, child);
|
||||
}
|
||||
|
||||
pub fn create(self: *Node, allocator: Allocator, val: T) !*Node {
|
||||
const child = Node.init(val);
|
||||
try self.children.append(allocator, child);
|
||||
return &self.children.items[self.children.items.len - 1];
|
||||
}
|
||||
};
|
||||
|
||||
pub fn init(val: T) @This() {
|
||||
return .{ .root = .init(val, null, 0) };
|
||||
return .{ .root = .init(val) };
|
||||
}
|
||||
|
||||
pub const DepthFirstIterator = struct {
|
||||
const State = enum {
|
||||
GoDeeper,
|
||||
GoBroader,
|
||||
};
|
||||
tree: *Tree(T),
|
||||
current: ?*Node,
|
||||
state: State,
|
||||
pub const PreOrderIterator = struct {
|
||||
pre_order: ArrayList(*Node),
|
||||
index: usize,
|
||||
|
||||
pub fn init(tree: *Tree(T)) DepthFirstIterator {
|
||||
return DepthFirstIterator{
|
||||
.tree = tree,
|
||||
.current = &tree.root,
|
||||
.state = State.GoDeeper,
|
||||
pub fn init(tree: *Tree(T), allocator: Allocator) !PreOrderIterator {
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
const arena_allocator = arena.allocator();
|
||||
|
||||
var stack = try ArrayList(*Node).initCapacity(arena_allocator, 1);
|
||||
stack.appendAssumeCapacity(&tree.root);
|
||||
|
||||
var pre_order = ArrayList(*Node).empty;
|
||||
|
||||
while (stack.items.len > 0) {
|
||||
if (stack.pop()) |tmp| {
|
||||
try pre_order.insert(allocator, 0, tmp);
|
||||
|
||||
for (0..tmp.children.items.len) |i| {
|
||||
try stack.append(arena_allocator, &tmp.children.items[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return .{
|
||||
.index = 0,
|
||||
.pre_order = pre_order,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn next(it: *DepthFirstIterator) ?*Node {
|
||||
// State machine
|
||||
while (it.current) |current| {
|
||||
switch (it.state) {
|
||||
State.GoDeeper => {
|
||||
// Follow child node until deepest possible level
|
||||
if (current.children.items.len > 0) {
|
||||
it.current = ¤t.children.items[0];
|
||||
} else {
|
||||
it.state = State.GoBroader;
|
||||
return current;
|
||||
}
|
||||
},
|
||||
State.GoBroader => {
|
||||
if (current.parent) |parent| {
|
||||
if (parent.children.items.len - 1 > (current.index)) {
|
||||
it.current = &parent.children.items[current.index + 1];
|
||||
it.state = .GoDeeper;
|
||||
} else {
|
||||
it.current = current.parent;
|
||||
return current.parent;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
}
|
||||
pub fn next(it: *PreOrderIterator) ?*Node {
|
||||
while (it.index < it.pre_order.items.len) {
|
||||
const val = it.pre_order.items[it.index];
|
||||
it.index += 1;
|
||||
return val;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn reset(it: *DepthFirstIterator) void {
|
||||
it.current = it.tree.root;
|
||||
pub fn deinit(self: *PreOrderIterator, allocator: Allocator) void {
|
||||
self.pre_order.deinit(allocator);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn depthFirstIterator(tree: *@This()) DepthFirstIterator {
|
||||
return DepthFirstIterator.init(tree);
|
||||
pub fn preOrderIterator(tree: *@This(), allocator: Allocator) !PreOrderIterator {
|
||||
return PreOrderIterator.init(tree, allocator);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *@This(), allocator: Allocator) void {
|
||||
var iterator = self.depthFirstIterator();
|
||||
pub const PostOrderIterator = struct {
|
||||
post_order: ArrayList(*Node),
|
||||
index: usize,
|
||||
|
||||
const Frame = struct {
|
||||
node: *Node,
|
||||
children_index: usize,
|
||||
};
|
||||
|
||||
pub fn init(tree: *Tree(T), allocator: Allocator) !PostOrderIterator {
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
const arena_allocator = arena.allocator();
|
||||
|
||||
var stack = ArrayList(Frame).empty;
|
||||
var current_root_index: usize = 0;
|
||||
var post_order = ArrayList(*Node).empty;
|
||||
|
||||
var curr_node: ?*Node = &tree.root;
|
||||
while (curr_node != null or stack.items.len > 0) {
|
||||
if (curr_node) |cur| {
|
||||
try stack.append(arena_allocator, .{
|
||||
.children_index = current_root_index,
|
||||
.node = cur,
|
||||
});
|
||||
|
||||
if (cur.children.items.len >= 1) {
|
||||
curr_node = &cur.children.items[0];
|
||||
} else {
|
||||
curr_node = null;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stack.pop()) |tmp| {
|
||||
try post_order.append(allocator, tmp.node);
|
||||
|
||||
while (stack.items.len > 0 and tmp.children_index == stack.items[stack.items.len - 1].node.children.items.len - 1) {
|
||||
if (stack.pop()) |tmp2| {
|
||||
try post_order.append(allocator, tmp2.node);
|
||||
}
|
||||
}
|
||||
|
||||
if (stack.items.len > 0 and stack.items[stack.items.len - 1].node.children.items.len > tmp.children_index + 1) {
|
||||
curr_node = &stack.items[stack.items.len - 1].node.children.items[tmp.children_index + 1];
|
||||
current_root_index = tmp.children_index + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return .{
|
||||
.index = 0,
|
||||
.post_order = post_order,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn next(it: *PostOrderIterator) ?*Node {
|
||||
while (it.index < it.post_order.items.len) {
|
||||
const val = it.post_order.items[it.index];
|
||||
it.index += 1;
|
||||
return val;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *PostOrderIterator, allocator: Allocator) void {
|
||||
self.post_order.deinit(allocator);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn postOrderIterator(tree: *@This(), allocator: Allocator) !PostOrderIterator {
|
||||
return PostOrderIterator.init(tree, allocator);
|
||||
}
|
||||
|
||||
pub const LevelOrderIterator = struct {
|
||||
level_order: ArrayList(*Node),
|
||||
index: usize,
|
||||
|
||||
pub fn init(tree: *Tree(T), allocator: Allocator) !LevelOrderIterator {
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
const arena_allocator = arena.allocator();
|
||||
|
||||
var stack = try ArrayList(*Node).initCapacity(arena_allocator, 1);
|
||||
stack.appendAssumeCapacity(&tree.root);
|
||||
|
||||
var level_order = ArrayList(*Node).empty;
|
||||
|
||||
while (stack.items.len > 0) {
|
||||
if (stack.pop()) |tmp| {
|
||||
try level_order.append(allocator, tmp);
|
||||
|
||||
for (0..tmp.children.items.len) |i| {
|
||||
try stack.append(arena_allocator, &tmp.children.items[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return .{
|
||||
.index = 0,
|
||||
.level_order = level_order,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn next(it: *LevelOrderIterator) ?*Node {
|
||||
while (it.index < it.level_order.items.len) {
|
||||
const val = it.level_order.items[it.index];
|
||||
it.index += 1;
|
||||
return val;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *LevelOrderIterator, allocator: Allocator) void {
|
||||
self.level_order.deinit(allocator);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn levelOrderIterator(tree: *@This(), allocator: Allocator) !LevelOrderIterator {
|
||||
return LevelOrderIterator.init(tree, allocator);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *@This(), allocator: Allocator) !void {
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
const arena_allocator = arena.allocator();
|
||||
|
||||
var iterator = try self.postOrderIterator(arena_allocator);
|
||||
while (iterator.next()) |node| {
|
||||
node.children.deinit(allocator);
|
||||
}
|
||||
@@ -131,20 +251,17 @@ test "Tree" {
|
||||
const UTree = Tree(u16);
|
||||
|
||||
var tree = UTree.init(10);
|
||||
defer tree.deinit(allocator);
|
||||
defer tree.deinit(allocator) catch {};
|
||||
|
||||
try tree.root.append(allocator, 20);
|
||||
try tree.root.append(allocator, 500);
|
||||
|
||||
var iterator = tree.depthFirstIterator();
|
||||
try tree.root.children.items[1].append(allocator, 999);
|
||||
|
||||
var iterator = try tree.levelOrderIterator(allocator);
|
||||
defer iterator.deinit(allocator);
|
||||
std.debug.print("\n", .{});
|
||||
while (iterator.next()) |node| {
|
||||
var accumulator: u32 = node.val;
|
||||
var current = node;
|
||||
while (current.parent) |parent| {
|
||||
accumulator *= parent.val;
|
||||
current = parent;
|
||||
}
|
||||
std.debug.print("Val: {} Acc: {}\n", .{ node.val, accumulator });
|
||||
std.debug.print("Val: {}\n", .{node.val});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user