From 8235f3dc7fb2a7b4d12b1de68249183e16688a66 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 12 Jun 2020 11:44:01 -0700 Subject: [PATCH] wip --- zig-ecs/src/ecs/component_storage.zig | 37 ++++++++++----------------- zig-ecs/src/ecs/sparse_set.zig | 17 +++++++++--- zig-ecs/src/ecs/utils.zig | 15 +++++++++++ zig-ecs/tests/groups_test.zig | 24 ++++++++--------- 4 files changed, 54 insertions(+), 39 deletions(-) diff --git a/zig-ecs/src/ecs/component_storage.zig b/zig-ecs/src/ecs/component_storage.zig index de9ee8f..b499a93 100644 --- a/zig-ecs/src/ecs/component_storage.zig +++ b/zig-ecs/src/ecs/component_storage.zig @@ -200,13 +200,26 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type) type { } /// Sort Entities or Components according to the given comparison function - pub fn sort(self: Self, comptime T: type, comptime sortFn: fn (void, T, T) bool) void { + pub fn sort(self: *Self, comptime T: type, comptime sortFn: fn (void, T, T) bool) void { std.debug.assert(T == EntityT or T == CompT); if (T == EntityT) { self.set.sortSub(sortFn, CompT, self.instances.items); } else if (T == CompT) { // essentially need to be able to call a sort method with a bound fn. That fn would then use sortFn along // with self.instances. + const Context = struct{ + self: *Self, + sortFn: fn (void, T, T) bool, + + fn sort(this: @This(), a: EntityT, b: EntityT) bool { + const real_a = this.self.getConst(a); + const real_b = this.self.getConst(b); + return this.sortFn({}, real_a, real_b); + } + }; + const context = Context{.self = self, .sortFn = sortFn}; + + self.set.sortSubSub(context, Context.sort, CompT, self.instances.items); // fn sorter(self: Self, a: T, b: T, sortFn) bool { // return sortFn(self.instances[a], self.instances[b]); // } @@ -357,25 +370,3 @@ test "sort empty component" { const asc_f32 = std.sort.asc(f32); const desc_f32 = std.sort.desc(f32); - -test "sort component" { - std.debug.warn("\n", .{}); - - var store = ComponentStorage(f32, u32).initPtr(std.testing.allocator); - defer store.deinit(); - - store.add(1, @as(f32, 1.1)); - store.add(2, @as(f32, 2.2)); - store.add(0, @as(f32, 0.0)); - - store.sort(f32, asc_f32); - for (store.raw()) |e, i| { - // std.debug.warn("{}: {}\n", .{i, e}); - // std.testing.expectEqual(@intCast(u32, i), e); - } - - store.sort(f32, desc_f32); - for (store.raw()) |e, i| { - // std.testing.expectEqual(counter, e); - } -} \ No newline at end of file diff --git a/zig-ecs/src/ecs/sparse_set.zig b/zig-ecs/src/ecs/sparse_set.zig index 9848973..a0fe045 100644 --- a/zig-ecs/src/ecs/sparse_set.zig +++ b/zig-ecs/src/ecs/sparse_set.zig @@ -95,8 +95,9 @@ pub fn SparseSet(comptime SparseT: type) type { pub fn contains(self: Self, sparse: SparseT) bool { const curr = self.page(sparse); - if (curr >= self.sparse.items.len) + if (curr >= self.sparse.items.len) { return false; + } // testing against maxInt permits to avoid accessing the packed array return curr < self.sparse.items.len and self.sparse.items[curr] != std.math.maxInt(SparseT); @@ -146,7 +147,7 @@ pub fn SparseSet(comptime SparseT: type) type { std.sort.insertionSort(SparseT, self.dense.items, {}, sortFn); for (self.dense.items) |sparse| { - // self.assure(self.page(sparse))[self.offset(sparse)] = @intCast(SparseT, sparse); + // sparse[page(packed[pos])][offset(packed[pos])] = entity_type(pos); self.sparse.items[self.page(sparse)] = @intCast(SparseT, sparse); } } @@ -156,11 +157,21 @@ pub fn SparseSet(comptime SparseT: type) type { utils.sortSub(SparseT, T, self.dense.items, sub_items, sortFn); for (self.dense.items) |sparse| { - // self.assure(self.page(sparse))[self.offset(sparse)] = @intCast(SparseT, sparse); + // sparse[page(packed[pos])][offset(packed[pos])] = entity_type(pos); self.sparse.items[self.page(sparse)] = @intCast(SparseT, sparse); } } + pub fn sortSubSub(self: *Self, context: var, comptime sortFn: fn (@TypeOf(context), SparseT, SparseT) bool, comptime T: type, sub_items: []T) void { + utils.sortSubSub(SparseT, T, self.dense.items, sub_items, context, sortFn); + + for (self.dense.items) |sparse, i| { + std.debug.warn("e: {}, dense: {}, instance: {}\n", .{sparse, self.dense.items[self.page(@intCast(u32, i))], sub_items[i]}); + // sparse[page(packed[pos])][offset(packed[pos])] = entity_type(pos); + self.sparse.items[self.dense.items[self.page(@intCast(u32, i))]] = @intCast(SparseT, sparse); + } + } + /// Sort entities according to their order in another sparse set. Other is the master in this case. pub fn respect(self: *Self, other: *Self) void { var pos = @as(SparseT, 0); diff --git a/zig-ecs/src/ecs/utils.zig b/zig-ecs/src/ecs/utils.zig index 2bdc03d..ba82c39 100644 --- a/zig-ecs/src/ecs/utils.zig +++ b/zig-ecs/src/ecs/utils.zig @@ -64,6 +64,21 @@ pub fn sortSub(comptime T1: type, comptime T2: type, items: []T1, sub_items: []T } } +pub fn sortSubSub(comptime T1: type, comptime T2: type, items: []T1, sub_items: []T2, context: var, comptime lessThan: fn (@TypeOf(context), lhs: T1, rhs: T1) bool) void { + var i: usize = 1; + while (i < items.len) : (i += 1) { + const x = items[i]; + const y = sub_items[i]; + var j: usize = i; + while (j > 0 and lessThan(context, x, items[j - 1])) : (j -= 1) { + items[j] = items[j - 1]; + sub_items[j] = sub_items[j - 1]; + } + items[j] = x; + sub_items[j] = y; + } +} + /// comptime string hashing for the type names pub fn typeId(comptime T: type) u32 { comptime return hashStringFnv(u32, @typeName(T)); diff --git a/zig-ecs/tests/groups_test.zig b/zig-ecs/tests/groups_test.zig index 7a3407a..70af802 100644 --- a/zig-ecs/tests/groups_test.zig +++ b/zig-ecs/tests/groups_test.zig @@ -14,14 +14,12 @@ const Rotation = struct { x: f32 = 0 }; fn printStore(store: var, name: []const u8) void { warn("--- {} ---\n", .{name}); for (store.set.dense.items) |e, i| { - warn("[{}] {}", .{e, store.set.sparse.items[store.set.page(store.set.dense.items[i])]}); + warn("e[{}] s[{}]{}", .{e, store.set.page(store.set.dense.items[i]), store.set.sparse.items[store.set.page(store.set.dense.items[i])]}); warn(" ({d:.2}) ", .{store.instances.items[i]}); } warn("\n", .{}); } -const asc_u32 = std.sort.asc(u32); -const desc_u32 = std.sort.desc(f32); test "sort component" { std.debug.warn("\n", .{}); @@ -29,24 +27,24 @@ test "sort component" { var store = ecs.ComponentStorage(f32, u32).initPtr(std.testing.allocator); defer store.deinit(); - store.add(1, @as(f32, 1.1)); - store.add(2, @as(f32, 2.2)); - store.add(0, @as(f32, 0.0)); + store.add(33, @as(f32, 3.3)); + store.add(22, @as(f32, 2.2)); + store.add(11, @as(f32, 1.1)); - printStore(store, "Fucker"); + printStore(store, "Fuckerrrr"); - store.sort(u32, asc_u32); - for (store.raw()) |e, i| { - // std.debug.warn("{}: {}\n", .{i, e}); - // std.testing.expectEqual(@intCast(u32, i), e); - } + // sort by entity + // comptime const asc_u32 = std.sort.asc(u32); + // store.sort(u32, asc_u32); - printStore(store, "Fucker"); + comptime const desc_u32 = std.sort.asc(f32); store.sort(f32, desc_u32); for (store.raw()) |e, i| { // std.testing.expectEqual(counter, e); } + + printStore(store, "Fuckerrrrr"); } test "nested OwningGroups add/remove components" {