297 lines
8.4 KiB
Zig
Raw Normal View History

2020-05-31 21:28:29 -07:00
const std = @import("std");
const utils = @import("utils.zig");
const Registry = @import("registry.zig").Registry;
const Storage = @import("registry.zig").Storage;
const Entity = @import("registry.zig").Entity;
2020-06-10 13:10:56 -07:00
/// single item view. Iterating raw() directly is the fastest way to get at the data. An iterator is also available to iterate
/// either the Entities or the Components. If T is sorted note that raw() will be in the reverse order so it should be looped
/// backwards. The iterators will return data in the sorted order though.
2020-05-31 21:28:29 -07:00
pub fn BasicView(comptime T: type) type {
return struct {
const Self = @This();
storage: *Storage(T),
pub fn init(storage: *Storage(T)) Self {
2020-06-01 22:25:27 -07:00
return Self{
2020-05-31 21:28:29 -07:00
.storage = storage,
};
}
pub fn len(self: Self) usize {
return self.storage.len();
}
/// Direct access to the array of components
pub fn raw(self: Self) []T {
return self.storage.raw();
}
/// Direct access to the array of entities
2020-06-09 10:21:42 -07:00
pub fn data(self: Self) []const Entity {
2020-05-31 21:28:29 -07:00
return self.storage.data();
}
/// Returns the object associated with an entity
pub fn get(self: Self, entity: Entity) *T {
return self.storage.get(entity);
}
2020-06-01 22:25:27 -07:00
2020-06-10 13:10:56 -07:00
pub fn getConst(self: *Self, entity: Entity) T {
2020-06-01 22:25:27 -07:00
return self.storage.getConst(entity);
}
2020-06-10 13:10:56 -07:00
pub fn entityIterator(self: Self) utils.ReverseSliceIterator(Entity) {
return self.storage.set.reverseIterator();
}
pub fn componentIterator(self: Self) utils.ReverseSliceIterator(T) {
return utils.ReverseSliceIterator(T).init(self.storage.instances.items);
}
2020-05-31 21:28:29 -07:00
};
}
2020-06-03 15:01:16 -07:00
pub fn MultiView(comptime n_includes: usize, comptime n_excludes: usize) type {
2020-05-31 21:28:29 -07:00
return struct {
const Self = @This();
2020-06-02 19:55:24 -07:00
registry: *Registry,
2020-06-01 22:25:27 -07:00
type_ids: [n_includes]u32,
exclude_type_ids: [n_excludes]u32,
2020-05-31 21:28:29 -07:00
pub const Iterator = struct {
view: *Self,
2020-06-10 13:10:56 -07:00
index: usize,
2020-05-31 21:28:29 -07:00
entities: *const []Entity,
pub fn init(view: *Self) Iterator {
2020-06-04 13:37:51 -07:00
const ptr = view.registry.components.getValue(view.type_ids[0]).?;
2020-06-10 13:10:56 -07:00
const entities = @intToPtr(*Storage(u8), ptr).dataPtr();
2020-05-31 21:28:29 -07:00
return .{
.view = view,
2020-06-10 13:10:56 -07:00
.index = entities.len,
.entities = entities,
2020-05-31 21:28:29 -07:00
};
}
pub fn next(it: *Iterator) ?Entity {
2020-06-10 13:10:56 -07:00
while (true) blk: {
if (it.index == 0) return null;
it.index -= 1;
2020-05-31 21:28:29 -07:00
const entity = it.entities.*[it.index];
// entity must be in all other Storages
for (it.view.type_ids) |tid| {
2020-06-04 13:37:51 -07:00
const ptr = it.view.registry.components.getValue(tid).?;
2020-06-01 22:25:27 -07:00
if (!@intToPtr(*Storage(u1), ptr).contains(entity)) {
2020-05-31 21:28:29 -07:00
break :blk;
}
}
2020-06-01 22:25:27 -07:00
// entity must not be in all other excluded Storages
for (it.view.exclude_type_ids) |tid| {
2020-06-04 13:37:51 -07:00
const ptr = it.view.registry.components.getValue(tid).?;
2020-06-01 22:25:27 -07:00
if (@intToPtr(*Storage(u1), ptr).contains(entity)) {
break :blk;
}
}
2020-05-31 21:28:29 -07:00
return entity;
}
}
// Reset the iterator to the initial index
pub fn reset(it: *Iterator) void {
2020-06-10 13:10:56 -07:00
it.index = it.entities.len;
2020-05-31 21:28:29 -07:00
}
};
2020-06-02 19:55:24 -07:00
pub fn init(registry: *Registry, type_ids: [n_includes]u32, exclude_type_ids: [n_excludes]u32) Self {
2020-05-31 21:28:29 -07:00
return Self{
2020-06-02 19:55:24 -07:00
.registry = registry,
2020-05-31 21:28:29 -07:00
.type_ids = type_ids,
2020-06-01 22:25:27 -07:00
.exclude_type_ids = exclude_type_ids,
2020-05-31 21:28:29 -07:00
};
}
pub fn get(self: *Self, comptime T: type, entity: Entity) *T {
2020-06-02 19:55:24 -07:00
return self.registry.assure(T).get(entity);
2020-05-31 21:28:29 -07:00
}
pub fn getConst(self: *Self, comptime T: type, entity: Entity) T {
2020-06-02 19:55:24 -07:00
return self.registry.assure(T).getConst(entity);
2020-05-31 21:28:29 -07:00
}
fn sort(self: *Self) void {
// get our component counts in an array so we can sort the type_ids based on how many entities are in each
2020-06-01 22:25:27 -07:00
var sub_items: [n_includes]usize = undefined;
2020-05-31 21:28:29 -07:00
for (self.type_ids) |tid, i| {
2020-06-04 13:37:51 -07:00
const ptr = self.registry.components.getValue(tid).?;
2020-05-31 21:28:29 -07:00
const store = @intToPtr(*Storage(u8), ptr);
sub_items[i] = store.len();
}
2020-06-11 22:34:25 -07:00
const asc_usize = struct {
fn sort(ctx: void, a: usize, b: usize) bool {
return a < b;
}
};
utils.sortSub(usize, u32, sub_items[0..], self.type_ids[0..], asc_usize.sort);
2020-05-31 21:28:29 -07:00
}
pub fn iterator(self: *Self) Iterator {
self.sort();
return Iterator.init(self);
}
};
}
test "single basic view" {
var store = Storage(f32).init(std.testing.allocator);
defer store.deinit();
store.add(3, 30);
store.add(5, 50);
store.add(7, 70);
var view = BasicView(f32).init(&store);
std.testing.expectEqual(view.len(), 3);
store.remove(7);
std.testing.expectEqual(view.len(), 2);
2020-06-10 13:10:56 -07:00
var i: usize = 0;
var iter = view.componentIterator();
while (iter.next()) |comp| {
if (i == 0) std.testing.expectEqual(comp, 50);
if (i == 1) std.testing.expectEqual(comp, 30);
i += 1;
}
i = 0;
var entIter = view.entityIterator();
while (entIter.next()) |ent| {
if (i == 0) {
std.testing.expectEqual(ent, 5);
std.testing.expectEqual(view.getConst(ent), 50);
}
if (i == 1) {
std.testing.expectEqual(ent, 3);
std.testing.expectEqual(view.getConst(ent), 30);
}
i += 1;
}
2020-05-31 21:28:29 -07:00
}
test "single basic view data" {
var store = Storage(f32).init(std.testing.allocator);
defer store.deinit();
store.add(3, 30);
store.add(5, 50);
store.add(7, 70);
var view = BasicView(f32).init(&store);
std.testing.expectEqual(view.get(3).*, 30);
2020-06-09 10:21:42 -07:00
for (view.data()) |entity, i| {
2020-05-31 21:28:29 -07:00
if (i == 0)
std.testing.expectEqual(entity, 3);
if (i == 1)
std.testing.expectEqual(entity, 5);
if (i == 2)
std.testing.expectEqual(entity, 7);
}
for (view.raw()) |data, i| {
if (i == 0)
std.testing.expectEqual(data, 30);
if (i == 1)
std.testing.expectEqual(data, 50);
if (i == 2)
std.testing.expectEqual(data, 70);
}
std.testing.expectEqual(view.len(), 3);
}
test "basic multi view" {
var reg = Registry.init(std.testing.allocator);
defer reg.deinit();
var e0 = reg.create();
var e1 = reg.create();
var e2 = reg.create();
reg.add(e0, @as(i32, -0));
reg.add(e1, @as(i32, -1));
reg.add(e2, @as(i32, -2));
reg.add(e0, @as(u32, 0));
reg.add(e2, @as(u32, 2));
2020-06-01 22:25:27 -07:00
var single_view = reg.view(.{u32}, .{});
var view = reg.view(.{ i32, u32 }, .{});
2020-05-31 21:28:29 -07:00
var iterated_entities: usize = 0;
var iter = view.iterator();
while (iter.next()) |entity| {
iterated_entities += 1;
}
std.testing.expectEqual(iterated_entities, 2);
iterated_entities = 0;
reg.remove(u32, e0);
iter.reset();
while (iter.next()) |entity| {
iterated_entities += 1;
}
std.testing.expectEqual(iterated_entities, 1);
2020-06-01 22:25:27 -07:00
}
test "basic multi view with excludes" {
var reg = Registry.init(std.testing.allocator);
defer reg.deinit();
var e0 = reg.create();
var e1 = reg.create();
var e2 = reg.create();
reg.add(e0, @as(i32, -0));
reg.add(e1, @as(i32, -1));
reg.add(e2, @as(i32, -2));
reg.add(e0, @as(u32, 0));
reg.add(e2, @as(u32, 2));
reg.add(e2, @as(u8, 255));
var view = reg.view(.{ i32, u32 }, .{u8});
var iterated_entities: usize = 0;
var iter = view.iterator();
while (iter.next()) |entity| {
iterated_entities += 1;
}
std.testing.expectEqual(iterated_entities, 1);
iterated_entities = 0;
reg.remove(u8, e2);
iter.reset();
while (iter.next()) |entity| {
iterated_entities += 1;
}
std.testing.expectEqual(iterated_entities, 2);
}