diff --git a/build.zig b/build.zig index f0aecc5..504b591 100644 --- a/build.zig +++ b/build.zig @@ -12,9 +12,13 @@ pub fn build(b: *std.build.Builder) !void { .output_name = "mapldtk", }); + const data_step = b.addOptions(); + data_step.addOptionFileSource("path", .{.generated = &ldtk.world_data }); + const mode = b.standardReleaseOptions(); const lib = b.addSharedLibrary("cart", "src/main.zig", .unversioned); - lib.step.dependOn(&ldtk.step); + lib.step.dependOn(&data_step.step); + lib.addPackage(data_step.getPackage("world_data")); lib.addPackage(assets); lib.setBuildMode(mode); lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); diff --git a/src/extract.zig b/src/extract.zig index 419cc7c..9f7e8d4 100644 --- a/src/extract.zig +++ b/src/extract.zig @@ -1,23 +1,37 @@ +const w4 = @import("wasm4.zig"); const std = @import("std"); const Map = @import("map.zig"); const Circuit = @import("circuit.zig"); const world = @import("world.zig"); const Level = world.Level; -const Level = world.AutoTile; +const AutoTile = world.AutoTile; +const CircuitType = world.CircuitType; -pub const ExtractOptions = struct { +pub const Options = struct { map: *Map, circuit: *Circuit, + alloc: std.mem.Allocator, + level: world.Level, + tileset: world.AutoTileset, }; +fn is_solid(tile: u7) bool { + return tile != 0 and tile != 1; +} + /// Extracts a compressed level into the map and circuit buffers -pub fn extractLevel(alloc: std.mem.Allocator, level: Level, opt: ExtractOptions) void { +pub fn extractLevel(opt: Options) !void { const map = opt.map; const circuit = opt.circuit; + const alloc = opt.alloc; + const level = opt.level; + const tileset = opt.tileset; + const width = level.width; const height = @divExact(@intCast(u16, level.tiles.len), level.width); const size = level.tiles.len; + map.map_size = .{ level.width, height }; circuit.map_size = .{ level.width, height }; @@ -29,23 +43,29 @@ pub fn extractLevel(alloc: std.mem.Allocator, level: Level, opt: ExtractOptions) for (level.tiles) |tile, i| { if (tile.is_tile) { - solid_map[i] = is_solid(tile.data.tile); - map.map[i] = tile.data.tile; + // solid_map[i] = is_solid(tile.data.tile); + map.tiles[i] = tile.data.tile; circuit_map[i] = .None; } else { - solid_map = tile.data.flags.solid; + solid_map[i] = tile.data.flags.solid; circuit_map[i] = @intToEnum(CircuitType, tile.data.flags.circuit); } } - var autotiles = try alloc.alloc(AutoTile, size); + var autotiles = try alloc.alloc(?AutoTile, size); defer alloc.free(autotiles); { var i: usize = 0; while (i < level.tiles.len) : (i += 1) { const x = @mod(i, width); - const y = @divTrunc(a, width); + const y = @divTrunc(i, width); + const stride = width; + + if (!solid_map[i]) { + autotiles[i] = null; + continue; + } const out_of_bounds = true; var north = false; @@ -56,11 +76,11 @@ pub fn extractLevel(alloc: std.mem.Allocator, level: Level, opt: ExtractOptions) // Check horizontal neighbors if (x == 0) { west = out_of_bounds; - } - else if (x == width - 1) { + east = solid_map[i + 1]; + } else if (x == width - 1) { + west = solid_map[i - 1]; east = out_of_bounds; - } - else { + } else { west = solid_map[i - 1]; east = solid_map[i + 1]; } @@ -68,13 +88,13 @@ pub fn extractLevel(alloc: std.mem.Allocator, level: Level, opt: ExtractOptions) // Check vertical neighbours if (y == 0) { north = out_of_bounds; - } - else if (y == height - 1) { + south = solid_map[i + stride]; + } else if (y == height - 1) { + north = solid_map[i - stride]; south = out_of_bounds; - } - else { - north = solid_map[i - width]; - south = solid_map[i + width]; + } else { + north = solid_map[i - stride]; + south = solid_map[i + stride]; } autotiles[i] = AutoTile{ @@ -86,7 +106,11 @@ pub fn extractLevel(alloc: std.mem.Allocator, level: Level, opt: ExtractOptions) } } - for (autotiles) |autotile, i| { - map.map[i] = tileset.lookup[autotile.to_u4()]; + for (autotiles) |autotile_opt, i| { + if (autotile_opt) |autotile| { + const li = autotile.to_u4(); + const tile = tileset.lookup[li]; + map.tiles[i] = tile; + } } } diff --git a/src/main.zig b/src/main.zig index 81206bf..0b966c8 100644 --- a/src/main.zig +++ b/src/main.zig @@ -29,7 +29,8 @@ export fn update() void { .Menu => menu.update(), .Game => game.update(time) catch |e| switch (e) { error.Overflow => showErr(@errorName(e)), - error.OutOfBounds => showErr(@errorName(e)), + // error.OutOfBounds => showErr(@errorName(e)), + error.EndOfStream => showErr(@errorName(e)), }, }; if (state != newState) { @@ -38,7 +39,9 @@ export fn update() void { .Menu => menu.start(), .Game => game.start() catch |e| switch (e) { error.Overflow => showErr(@errorName(e)), - error.OutOfBounds => showErr(@errorName(e)), + // error.OutOfBounds => showErr(@errorName(e)), + error.EndOfStream => showErr(@errorName(e)), + error.OutOfMemory => showErr(@errorName(e)), }, } } diff --git a/src/rewrite.zig b/src/rewrite.zig index 9062679..fc60eb2 100644 --- a/src/rewrite.zig +++ b/src/rewrite.zig @@ -1,5 +1,6 @@ -const world_data = @import("world_data"); -const Circuit = @import("map.zig"); +const extract = @import("extract.zig"); +const world_data = @embedFile(@import("world_data").path); +const Circuit = @import("circuit.zig"); const input = @import("input.zig"); const Map = @import("map.zig"); const State = @import("main.zig").State; @@ -17,27 +18,55 @@ var map_buf: [400]u8 = undefined; var map: Map = undefined; var circuit_lvl_buf: [400]u8 = undefined; -var circuit_buf : [400]u8 = undefined; +var circuit_buf: [400]u8 = undefined; var circuit: Circuit = undefined; -var level_size = Vec2{20, 20}; +var level_size = Vec2{ 20, 20 }; -pub fn start() void { +pub fn start() !void { circuit = try Circuit.init(&circuit_buf, &circuit_lvl_buf, level_size); map = Map.init(&map_buf, level_size); - const extract_opt = world.ExtractOptions{ + var stream = std.io.FixedBufferStream([]const u8){ + .pos = 0, + .buffer = world_data, + }; + const world_reader = stream.reader(); + + const header = try world.LevelHeader.read(world_reader); + var tile_buf: [4096]world.TileStore = undefined; + try header.readTiles(world_reader, &tile_buf); + + const level = world.Level.init(header, &tile_buf); + + try extract.extractLevel(.{ + .alloc = frame_alloc, + .level = level, .map = &map, .circuit = &circuit, - }; - - const world_reader = std.io.FixedBufferStream([]const u8).reader(); - const level = world_reader.readStruct(world.Level); - - world.extractLevel(frame_alloc, level, extract_opt); + .tileset = world.AutoTileset{ .lookup = .{ + 35, // Island + 51, // North + 52, // West + 55, // West-North + 50, // East + 53, // East-North + 19, // East-West + 54, // East-West-North + 49, // South + 20, // South-North + 23, // South-West + 39, // South-West-North + 21, // South-East + 37, // South-East-North + 22, // South-East-West + 0, // South-East-West-North + }}, + }); } -pub fn update() State { +pub fn update(time: usize) !State { + _ = time; // Reset the frame allocator frame_fba.reset(); @@ -45,7 +74,7 @@ pub fn update() State { w4.rect(Vec2{ 0, 0 }, Vec2{ 160, 160 }); w4.DRAW_COLORS.* = 0x0001; - const camera = Vec2{0, 0}; + const camera = Vec2{ 0, 0 }; map.draw(camera); circuit.draw(camera); diff --git a/src/world.zig b/src/world.zig index 4db704c..d7f8bf2 100644 --- a/src/world.zig +++ b/src/world.zig @@ -39,7 +39,7 @@ pub const TileStore = struct { pub fn fromByte(byte: u8) TileStore { const is_tile = (1 & byte) > 0; if (is_tile) { - const tile = @intCast(u7, (~1 & byte) >> 1); + const tile = @intCast(u7, (~@as(u7, 1) & byte) >> 1); return TileStore{ .is_tile = is_tile, .data = .{ .tile = tile }, @@ -84,7 +84,7 @@ pub const LevelHeader = struct { std.debug.assert(buf.len > header.size); var i: usize = 0; while (i < header.size) : (i += 1) { - buf[i] = TileStore.fromByte(reader.readByte()); + buf[i] = TileStore.fromByte(try reader.readByte()); } } }; @@ -94,14 +94,23 @@ pub const Level = struct { world_y: u8, width: u16, tiles: []TileStore, + + pub fn init(header: LevelHeader, buf: []TileStore) Level { + return Level { + .world_x = header.world_x, + .world_y = header.world_y, + .width = header.width, + .tiles = buf[0..header.size], + }; + } }; // AutoTile algorithm datatypes pub const AutoTile = packed struct { North: bool, West: bool, - South: bool, East: bool, + South: bool, pub fn to_u4(autotile: AutoTile) u4 { return @bitCast(u4, autotile); diff --git a/tools/LDtkImport.zig b/tools/LDtkImport.zig index 41fe15b..7e15a36 100644 --- a/tools/LDtkImport.zig +++ b/tools/LDtkImport.zig @@ -12,6 +12,7 @@ step: std.build.Step, builder: *std.build.Builder, source_path: std.build.FileSource, output_name: []const u8, +world_data: std.build.GeneratedFile, pub fn create(b: *std.build.Builder, opt: struct { source_path: std.build.FileSource, @@ -23,7 +24,9 @@ pub fn create(b: *std.build.Builder, opt: struct { .builder = b, .source_path = opt.source_path, .output_name = opt.output_name, + .world_data = undefined, }; + result.*.world_data = std.build.GeneratedFile{ .step = &result.*.step }; return result; } @@ -136,4 +139,6 @@ fn make(step: *std.build.Step) !void { else => return e, }; try cwd.writeFile(output, data.items); + + this.world_data.path = output; }