Use grid of levels to improve performance

Makes Wired run at full speed on the RG351M.
master
LeRoyce Pearson 2022-01-23 17:17:59 -07:00
parent 77a3fb166e
commit 3c3c9b4ddc
3 changed files with 23 additions and 77 deletions

View File

@ -172,16 +172,14 @@ fn get_plugs(tile: u8) Plugs {
} }
pub fn get_cell(this: @This(), cell: Cell) ?u8 { pub fn get_cell(this: @This(), cell: Cell) ?u8 {
if (this.cell_map.get_const(cell)) |c| return c.tile; const i = this.indexOf(cell) orelse return null;
const c = cell;
if (c[0] < 0 or c[0] > this.map_size[0] or c[1] > this.map_size[1] or c[1] < 0) return null;
const i = @intCast(usize, @mod(c[0], this.map_size[0]) + (c[1] * this.map_size[1]));
return if (this.map[i] != 0) this.map[i] - 1 else null; return if (this.map[i] != 0) this.map[i] - 1 else null;
} }
pub fn set_cell(this: *@This(), cell: Cell, tile: u8) void { pub fn set_cell(this: *@This(), cell: Cell, tile: u8) void {
var cellData = CellData{ .tile = tile }; const i = this.indexOf(cell) orelse return;
this.cell_map.set(cell, cellData); this.map[i] = tile + 1;
this.levels[i] = 0;
} }
const MAXCELLS = 400; const MAXCELLS = 400;
@ -190,38 +188,30 @@ const MAXSOURCES = 10;
const MAXDOORS = 40; const MAXDOORS = 40;
const MAXLOGIC = 40; const MAXLOGIC = 40;
const CellData = struct { level: u8 = 0, tile: u8 }; pub const CellData = struct { level: u8 = 0, tile: u8 };
const CellMap = util.Map(Cell, CellData, MAXCELLS);
const BridgeState = struct { cells: [2]Cell, id: usize, enabled: bool }; const BridgeState = struct { cells: [2]Cell, id: usize, enabled: bool };
const DoorState = struct { cell: Cell, enabled: bool }; const DoorState = struct { cell: Cell, enabled: bool };
map: []const u8, /// Tile id of the tiles
map: []u8,
/// Logic levels of the tiles
levels: []u8,
map_size: Vec2, map_size: Vec2,
cell_map: CellMap,
bridges: std.BoundedArray(BridgeState, MAXBRIDGES), bridges: std.BoundedArray(BridgeState, MAXBRIDGES),
sources: std.BoundedArray(Cell, MAXSOURCES), sources: std.BoundedArray(Cell, MAXSOURCES),
doors: std.BoundedArray(DoorState, MAXDOORS), doors: std.BoundedArray(DoorState, MAXDOORS),
logic_map: std.BoundedArray(Cell, MAXLOGIC),
pub fn init(map: []const u8, map_size: Vec2) @This() { pub fn init(map: []u8, levels: []u8, map_size: Vec2) @This() {
std.debug.assert(map.len == levels.len);
var this = @This(){ var this = @This(){
.map = map, .map = map,
.levels = levels,
.map_size = map_size, .map_size = map_size,
.cell_map = CellMap.init(),
.bridges = std.BoundedArray(BridgeState, MAXBRIDGES).init(0) catch unreachable, .bridges = std.BoundedArray(BridgeState, MAXBRIDGES).init(0) catch unreachable,
.sources = std.BoundedArray(Cell, MAXSOURCES).init(0) catch unreachable, .sources = std.BoundedArray(Cell, MAXSOURCES).init(0) catch unreachable,
.doors = std.BoundedArray(DoorState, MAXDOORS).init(0) catch unreachable, .doors = std.BoundedArray(DoorState, MAXDOORS).init(0) catch unreachable,
.logic_map = std.BoundedArray(Cell, MAXLOGIC).init(0) catch unreachable,
}; };
for (map) |tile, index| {
if (is_logic(tile)) {
const i = @intCast(i32, index);
const cell = Cell{ @mod(i, this.map_size[0]), @divTrunc(i, this.map_size[0]) };
// w4.tracef("%d, %d: %d", cell[0], cell[1], this.logic_map.len);
this.logic_map.append(cell) catch unreachable;
}
}
return this; return this;
} }
@ -231,12 +221,8 @@ pub fn indexOf(this: @This(), cell: Cell) ?usize {
} }
pub fn enable(this: *@This(), cell: Cell) void { pub fn enable(this: *@This(), cell: Cell) void {
if (this.cell_map.get(cell)) |c| { const i = this.indexOf(cell) orelse return;
c.level += 1; this.levels[i] += 1;
return;
}
const t = this.get_cell(cell) orelse return;
this.cell_map.set(cell, .{ .tile = t, .level = 1 });
} }
pub fn bridge(this: *@This(), cells: [2]Cell, bridgeID: usize) void { pub fn bridge(this: *@This(), cells: [2]Cell, bridgeID: usize) void {
@ -276,10 +262,8 @@ pub fn enabledDoors(this: @This()) std.BoundedArray(Cell, MAXDOORS) {
} }
pub fn isEnabled(this: @This(), cell: Cell) bool { pub fn isEnabled(this: @This(), cell: Cell) bool {
if (this.cell_map.get_const(cell)) |c| { const i = this.indexOf(cell) orelse return false;
return c.level >= 1; return this.levels[i] >= 1;
}
return false;
} }
pub fn toggle(this: *@This(), c: Cell) void { pub fn toggle(this: *@This(), c: Cell) void {
@ -293,9 +277,7 @@ pub fn toggle(this: *@This(), c: Cell) void {
} }
pub fn clear(this: *@This()) void { pub fn clear(this: *@This()) void {
for (this.cell_map.values.slice()) |*cell| { std.mem.set(u8, this.levels, 0);
cell.level = 0;
}
for (this.doors.slice()) |*door| { for (this.doors.slice()) |*door| {
door.enabled = false; door.enabled = false;
} }
@ -335,11 +317,8 @@ pub fn fill(this: *@This()) usize {
if (get_logic(tile)) |logic| { if (get_logic(tile)) |logic| {
// TODO: implement other logic (though I'm pretty sure that requires a graph...) // TODO: implement other logic (though I'm pretty sure that requires a graph...)
if (logic != .And) continue; if (logic != .And) continue;
if (this.cell_map.get(cell)) |data| { if (this.levels[index] < 2) continue;
// Skip current loop if and isn't high enough q.insert(cell + util.Dir.up);
if (data.level < 2) continue;
q.insert(cell + util.Dir.up);
}
} }
for (get_outputs(tile)) |conductor, i| { for (get_outputs(tile)) |conductor, i| {
if (!conductor) continue; if (!conductor) continue;

View File

@ -173,6 +173,8 @@ const Coin = struct { pos: Pos, sprite: Sprite, anim: Anim, area: AABB };
var coins = std.BoundedArray(Coin, 20).init(0) catch unreachable; var coins = std.BoundedArray(Coin, 20).init(0) catch unreachable;
var score: u8 = 0; var score: u8 = 0;
var solids_mutable = assets.solid; var solids_mutable = assets.solid;
var conduit_mutable = assets.conduit;
var conduitLevels_mutable: [conduit_mutable.len]u8 = undefined;
const anim_store = struct { const anim_store = struct {
const stand = Anim.frame(8); const stand = Anim.frame(8);
@ -203,7 +205,8 @@ fn showErr(msg: []const u8) noreturn {
export fn start() void { export fn start() void {
particles = ParticleSystem.init(); particles = ParticleSystem.init();
circuit = Circuit.init(&assets.conduit, assets.conduit_size); std.mem.set(u8, &conduitLevels_mutable, 0);
circuit = Circuit.init(&conduit_mutable, &conduitLevels_mutable, assets.conduit_size);
map = Map.init(&solids_mutable, assets.solid_size); map = Map.init(&solids_mutable, assets.solid_size);
camera = @divTrunc(assets.spawn, @splat(2, @as(i32, 20))) * @splat(2, @as(i32, 20)); camera = @divTrunc(assets.spawn, @splat(2, @as(i32, 20))) * @splat(2, @as(i32, 20));

View File

@ -81,39 +81,3 @@ pub fn Queue(comptime T: type, len: usize) type {
}; };
} }
pub fn Map(comptime K: type, comptime V: type, len: usize) type {
return struct {
keys: std.BoundedArray(K, len),
values: std.BoundedArray(V, len),
pub fn init() @This() {
return @This(){
.keys = std.BoundedArray(K, len).init(0) catch unreachable,
.values = std.BoundedArray(V, len).init(0) catch unreachable,
};
}
pub fn get(this: *@This(), key: K) ?*V {
for (this.keys.slice()) |k, i| {
if (@reduce(.And, key == k)) {
return &this.values.slice()[i];
}
}
return null;
}
pub fn get_const(this: @This(), key: Cell) ?V {
for (this.keys.constSlice()) |k, i| {
if (@reduce(.And, key == k)) {
return this.values.constSlice()[i];
}
}
return null;
}
pub fn set(this: *@This(), key: K, new: V) void {
if (this.get(key)) |v| {
v.* = new;
} else {
this.keys.append(key) catch unreachable;
this.values.append(new) catch unreachable;
}
}
};
}