diff --git a/build.zig b/build.zig index 7bc8d70..2c36892 100644 --- a/build.zig +++ b/build.zig @@ -55,7 +55,7 @@ pub fn build(b: *Build) void { var dep: std.Build.Dependency = .{ .builder = b }; const feature_test_cart = add_cart(&dep, b, .{ .name = "feature_test", - .optimize = .ReleaseSmall, + .optimize = optimize, .root_source_file = .{ .path = "samples/feature_test.zig" }, }); feature_test_cart.install(b); diff --git a/docs/introduction/README.md b/docs/introduction/README.md index c421757..13b44ad 100644 --- a/docs/introduction/README.md +++ b/docs/introduction/README.md @@ -49,10 +49,6 @@ Once you're happy with what you've made, read on to learn how to flash your code ## Hard(ware) mode -**Please wait until the afternoon before trying to upload programs onto badges as the badge is still being worked on.** - -Currently, only the neopixels are functional. - ### Power and Boot Your badge can be powered via the USB-C port, but to allow cordless use of the badge, you've been provided with a battery and two pieces of velcro. diff --git a/docs/introduction/build.zig b/docs/introduction/build.zig index ca6048d..a464760 100644 --- a/docs/introduction/build.zig +++ b/docs/introduction/build.zig @@ -5,7 +5,7 @@ pub fn build(b: *std.Build) void { const dep = b.dependency("sycl-badge", .{}); const feature_test_cart = badge.add_cart(dep, b, .{ .name = "hello", - .optimize = .ReleaseSmall, + .optimize = b.standardOptimizeOption(.{}), .root_source_file = .{ .path = "src/hello.zig" }, }); const watch_run_step = feature_test_cart.install_with_watcher(dep, b, .{}); diff --git a/samples/feature_test.zig b/samples/feature_test.zig index 817a59d..5bbd965 100644 --- a/samples/feature_test.zig +++ b/samples/feature_test.zig @@ -56,11 +56,11 @@ export fn update() void { green_565 -%= 1; } - if (cart.controls.left) { - write_stored_number(read_stored_number() -| 1); - } else if (cart.controls.right) { - write_stored_number(read_stored_number() +| 1); - } + // if (cart.controls.left) { + // write_stored_number(read_stored_number() -| 1); + // } else if (cart.controls.right) { + // write_stored_number(read_stored_number() +| 1); + // } cart.red_led.* = cart.controls.click; @@ -76,9 +76,9 @@ export fn update() void { for (cart.neopixels, 0..) |*np, i| { np.* = .{ - .r = @intFromFloat(@as(f32, @floatFromInt(i)) / 5 * 255), - .g = @intFromFloat(@as(f32, @floatFromInt(cart.light_level.*)) / std.math.maxInt(u12) * 255), - .b = @intFromFloat(@as(f32, @floatFromInt(i)) / 5 * 255), + .r = @intFromFloat(@as(f32, @floatFromInt(i)) / 5 * 20), + .g = @intFromFloat(@as(f32, @floatFromInt(cart.light_level.*)) / std.math.maxInt(u12) * 20), + .b = @intFromFloat(@as(f32, @floatFromInt(i)) / 5 * 20), }; } diff --git a/src/badge/cart.zig b/src/badge/cart.zig index 908e6cb..f5294e7 100644 --- a/src/badge/cart.zig +++ b/src/badge/cart.zig @@ -204,10 +204,20 @@ fn User(comptime T: type) type { }; } +fn point(x: usize, y: usize, color: api.DisplayColor) void { + api.framebuffer[y * api.screen_width + x] = color; +} + +fn pointUnclipped(x: i32, y: i32, color: api.DisplayColor) void { + if (x >= 0 and x < api.screen_width and y >= 0 and y < api.screen_height) { + point(@intCast(x), @intCast(y), color); + } +} + fn blit( - sprite: [*]const User(u8), - x: i32, - y: i32, + sprite: [*]const User(api.DisplayColor), + dst_x: i32, + dst_y: i32, rest: *const extern struct { width: User(u32), height: User(u32), @@ -224,15 +234,43 @@ fn blit( const stride = rest.stride.load(); const flags = rest.flags.load(); - _ = sprite; - _ = x; - _ = y; - _ = width; - _ = height; - _ = src_x; - _ = src_y; - _ = stride; - _ = flags; + const signed_width: i32 = @intCast(width); + const signed_height: i32 = @intCast(height); + + // Clip rectangle to screen + const flip_x, const clip_x_min: u32, const clip_y_min: u32, const clip_x_max: u32, const clip_y_max: u32 = + if (flags.rotate) .{ + !flags.flip_x, + @intCast(@max(0, dst_y) - dst_y), + @intCast(@max(0, dst_x) - dst_x), + @intCast(@min(signed_width, @as(i32, @intCast(api.screen_height)) - dst_y)), + @intCast(@min(signed_height, @as(i32, @intCast(api.screen_width)) - dst_x)), + } else .{ + flags.flip_x, + @intCast(@max(0, dst_x) - dst_x), + @intCast(@max(0, dst_y) - dst_y), + @intCast(@min(signed_width, @as(i32, @intCast(api.screen_width)) - dst_x)), + @intCast(@min(signed_height, @as(i32, @intCast(api.screen_height)) - dst_y)), + }; + + for (clip_y_min..clip_y_max) |y| { + for (clip_x_min..clip_x_max) |x| { + const signed_x: i32 = @intCast(x); + const signed_y: i32 = @intCast(y); + + // Calculate sprite target coords + const tx: u32 = @intCast(dst_x + (if (flags.rotate) signed_y else signed_x)); + const ty: u32 = @intCast(dst_y + (if (flags.rotate) signed_x else signed_y)); + + // Calculate sprite source coords + const sx = src_x + @as(u32, @intCast((if (flip_x) signed_width - signed_x - 1 else signed_x))); + const sy = src_y + @as(u32, @intCast((if (flags.flip_y) signed_height - signed_y - 1 else signed_y))); + + const index = sy * stride + sx; + + point(tx, ty, sprite[index].load()); + } + } } fn line( @@ -247,11 +285,34 @@ fn line( const y2 = rest.y2.load(); const color = rest.color.load(); - _ = x1; - _ = y1; - _ = x2; - _ = y2; - _ = color; + var x1_moving = x1; + var y1_adjusted, const y2_adjusted = if (y1 > y2) + .{ y2, y1 } + else + .{ y1, y2 }; + + const dx: i32 = @intCast(@abs(x2 - x1_moving)); + const sx: i32 = if (x1_moving < x2) 1 else -1; + const dy = y2_adjusted - y1_adjusted; + var err: i32 = @divTrunc(if (dx > dy) dx else -dy, 2); + var e2: i32 = 0; + + while (true) { + pointUnclipped(x1_moving, y1_adjusted, color); + + if (x1_moving == x2 and y1_adjusted == y2_adjusted) { + break; + } + e2 = err; + if (e2 > -dx) { + err -= dy; + x1_moving += sx; + } + if (e2 < dy) { + err += dx; + y1_adjusted += 1; + } + } } fn oval( @@ -268,12 +329,80 @@ fn oval( const stroke_color = rest.stroke_color.load(); const fill_color = rest.fill_color.load(); - _ = x; - _ = y; - _ = width; - _ = height; - _ = stroke_color; - _ = fill_color; + const signed_width: i32 = @intCast(width); + const signed_height: i32 = @intCast(height); + + var a = signed_width - 1; + const b = signed_height - 1; + var b1 = @rem(b, 2); // Compensates for precision loss when dividing + + var north = y + @divFloor(signed_height, 2); // Precision loss here + var west = x; + var east = x + signed_width - 1; + var south = north - b1; // Compensation here. Moves the bottom line up by + // one (overlapping the top line) for even heights + + const a2 = a * a; + const b2 = b * b; + + // Error increments. Also known as the decision parameters + var dx = 4 * (1 - a) * b2; + var dy = 4 * (b1 + 1) * a2; + + // Error of 1 step + var err = dx + dy + b1 * a2; + + a = 8 * a2; + b1 = 8 * b2; + + while (true) { + if (stroke_color.unwrap()) |sc| { + pointUnclipped(east, north, sc); // I. Quadrant + pointUnclipped(west, north, sc); // II. Quadrant + pointUnclipped(west, south, sc); // III. Quadrant + pointUnclipped(east, south, sc); // IV. Quadrant + } + + const oval_start = west + 1; + const len = east - oval_start; + + if (fill_color != .none and len > 0) { // Only draw fill if the length from west to east is not 0 + hline(oval_start, north, @intCast(east - oval_start), fill_color.unwrap().?); // I and III. Quadrant + hline(oval_start, south, @intCast(east - oval_start), fill_color.unwrap().?); // II and IV. Quadrant + } + + const err2 = 2 * err; + + if (err2 <= dy) { + // Move vertical scan + north += 1; + south -= 1; + dy += a; + err += dy; + } + + if (err2 >= dx or err2 > dy) { + // Move horizontal scan + west += 1; + east -= 1; + dx += b1; + err += dx; + } + + if (!(west <= east)) break; + } + + if (stroke_color.unwrap()) |sc| { + // Make sure north and south have moved the entire way so top/bottom aren't missing + while (north - south < signed_height) { + pointUnclipped(west - 1, north, sc); // II. Quadrant + pointUnclipped(east + 1, north, sc); // I. Quadrant + north += 1; + pointUnclipped(west - 1, south, sc); // III. Quadrant + pointUnclipped(east + 1, south, sc); // IV. Quadrant + south -= 1; + } + } } fn rect( @@ -287,17 +416,26 @@ fn rect( }, ) callconv(.C) void { const height = rest.height.load(); - const stroke_color = rest.stroke_color.load(); - const fill_color = rest.fill_color.load(); + const stroke_color = rest.stroke_color.load().unwrap(); + const fill_color = rest.fill_color.load().unwrap(); - _ = x; - _ = y; - _ = width; - _ = height; - _ = stroke_color; - _ = fill_color; + if (stroke_color) |sc| { + hline(x, y, width, sc); + hline(x, y + @as(i32, @intCast(height)), width + 1, sc); + + vline(x, y, height, sc); + vline(x + @as(i32, @intCast(width)), y, height, sc); + } + + if (fill_color) |fc| { + for (@as(u32, @intCast(y)) + 1..@as(u32, @intCast(y)) + height) |yy| { + hline(x + 1, @intCast(yy), width - 1, fc); + } + } } +const font = @import("font.zig").font; + fn text( str_ptr: [*]const User(u8), str_len: usize, @@ -308,16 +446,42 @@ fn text( background_color: User(api.DisplayColor.Optional), }, ) callconv(.C) void { - const str = str_ptr[0..str_len]; + // const str = str_ptr[0].load(); const y = rest.y.load(); const text_color = rest.text_color.load(); const background_color = rest.background_color.load(); - _ = str; - _ = x; - _ = y; - _ = text_color; - _ = background_color; + const colors = &[_]api.DisplayColor.Optional{ text_color, background_color }; + + var char_x_offset = x; + var char_y_offset = y; + + for (0..str_len) |char_idx| { + const char = str_ptr[char_idx].load(); + + if (char == 10) { + char_y_offset += 8; + char_x_offset = x; + } else if (char >= 32 and char <= 255) { + const base = (@as(usize, char) - 32) * 64; + for (0..8) |y_offset| { + const dst_y = char_y_offset + @as(i32, @intCast(y_offset)); + for (0..8) |x_offset| { + const dst_x = char_x_offset + @as(i32, @intCast(x_offset)); + + const color = colors[std.mem.readPackedIntNative(u1, &font, base + y_offset * 8 + (7 - x_offset))]; + if (color.unwrap()) |dc| { + // TODO: this is slow; check bounds once instead + pointUnclipped(dst_x, dst_y, dc); + } + } + } + + char_x_offset += 8; + } else { + char_x_offset += 8; + } + } } fn hline( @@ -326,10 +490,13 @@ fn hline( len: u32, color: api.DisplayColor, ) callconv(.C) void { - _ = x; - _ = y; - _ = len; - _ = color; + if (y < 0 or y >= api.screen_height) return; + + const clamped_x: u32 = @intCast(std.math.clamp(x, 0, @as(i32, @intCast(api.screen_width - 1)))); + const clamped_len = @min(clamped_x + len, api.screen_width) - clamped_x; + + const y_offset = api.screen_width * @as(u32, @intCast(y)); + @memset(api.framebuffer[y_offset + clamped_x ..][0..clamped_len], color); } fn vline( @@ -338,10 +505,14 @@ fn vline( len: u32, color: api.DisplayColor, ) callconv(.C) void { - _ = x; - _ = y; - _ = len; - _ = color; + if (y + @as(i32, @intCast(len)) <= 0 or x < 0 or x >= @as(i32, @intCast(api.screen_width))) return; + + const start_y: u32 = @intCast(@max(0, y)); + const end_y: u32 = @intCast(@min(api.screen_height, y + @as(i32, @intCast(len)))); + + for (start_y..end_y) |yy| { + point(@intCast(x), yy, color); + } } fn tone( diff --git a/src/badge/font.zig b/src/badge/font.zig new file mode 100644 index 0000000..dc290af --- /dev/null +++ b/src/badge/font.zig @@ -0,0 +1,226 @@ +pub const font = [_]u8{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc7, 0xc7, 0xc7, 0xcf, 0xcf, 0xff, 0xcf, 0xff, + 0x93, 0x93, 0x93, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x93, 0x01, 0x93, 0x93, 0x93, 0x01, 0x93, 0xff, + 0xef, 0x83, 0x2f, 0x83, 0xe9, 0x03, 0xef, 0xff, + 0x9d, 0x5b, 0x37, 0xef, 0xd9, 0xb5, 0x73, 0xff, + 0x8f, 0x27, 0x27, 0x8f, 0x25, 0x33, 0x81, 0xff, + 0xcf, 0xcf, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf3, 0xe7, 0xcf, 0xcf, 0xcf, 0xe7, 0xf3, 0xff, + 0x9f, 0xcf, 0xe7, 0xe7, 0xe7, 0xcf, 0x9f, 0xff, + 0xff, 0x93, 0xc7, 0x01, 0xc7, 0x93, 0xff, 0xff, + 0xff, 0xe7, 0xe7, 0x81, 0xe7, 0xe7, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xcf, 0x9f, + 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xcf, 0xff, + 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f, 0xff, + 0xc7, 0xb3, 0x39, 0x39, 0x39, 0x9b, 0xc7, 0xff, + 0xe7, 0xc7, 0xe7, 0xe7, 0xe7, 0xe7, 0x81, 0xff, + 0x83, 0x39, 0xf1, 0xc3, 0x87, 0x1f, 0x01, 0xff, + 0x81, 0xf3, 0xe7, 0xc3, 0xf9, 0x39, 0x83, 0xff, + 0xe3, 0xc3, 0x93, 0x33, 0x01, 0xf3, 0xf3, 0xff, + 0x03, 0x3f, 0x03, 0xf9, 0xf9, 0x39, 0x83, 0xff, + 0xc3, 0x9f, 0x3f, 0x03, 0x39, 0x39, 0x83, 0xff, + 0x01, 0x39, 0xf3, 0xe7, 0xcf, 0xcf, 0xcf, 0xff, + 0x87, 0x3b, 0x1b, 0x87, 0x61, 0x79, 0x83, 0xff, + 0x83, 0x39, 0x39, 0x81, 0xf9, 0xf3, 0x87, 0xff, + 0xff, 0xcf, 0xcf, 0xff, 0xcf, 0xcf, 0xff, 0xff, + 0xff, 0xcf, 0xcf, 0xff, 0xcf, 0xcf, 0x9f, 0xff, + 0xf3, 0xe7, 0xcf, 0x9f, 0xcf, 0xe7, 0xf3, 0xff, + 0xff, 0xff, 0x01, 0xff, 0x01, 0xff, 0xff, 0xff, + 0x9f, 0xcf, 0xe7, 0xf3, 0xe7, 0xcf, 0x9f, 0xff, + 0x83, 0x01, 0x39, 0xf3, 0xc7, 0xff, 0xc7, 0xff, + 0x83, 0x7d, 0x45, 0x55, 0x41, 0x7f, 0x83, 0xff, + 0xc7, 0x93, 0x39, 0x39, 0x01, 0x39, 0x39, 0xff, + 0x03, 0x39, 0x39, 0x03, 0x39, 0x39, 0x03, 0xff, + 0xc3, 0x99, 0x3f, 0x3f, 0x3f, 0x99, 0xc3, 0xff, + 0x07, 0x33, 0x39, 0x39, 0x39, 0x33, 0x07, 0xff, + 0x01, 0x3f, 0x3f, 0x03, 0x3f, 0x3f, 0x01, 0xff, + 0x01, 0x3f, 0x3f, 0x03, 0x3f, 0x3f, 0x3f, 0xff, + 0xc1, 0x9f, 0x3f, 0x31, 0x39, 0x99, 0xc1, 0xff, + 0x39, 0x39, 0x39, 0x01, 0x39, 0x39, 0x39, 0xff, + 0x81, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x81, 0xff, + 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0x39, 0x83, 0xff, + 0x39, 0x33, 0x27, 0x0f, 0x07, 0x23, 0x31, 0xff, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x81, 0xff, + 0x39, 0x11, 0x01, 0x01, 0x29, 0x39, 0x39, 0xff, + 0x39, 0x19, 0x09, 0x01, 0x21, 0x31, 0x39, 0xff, + 0x83, 0x39, 0x39, 0x39, 0x39, 0x39, 0x83, 0xff, + 0x03, 0x39, 0x39, 0x39, 0x03, 0x3f, 0x3f, 0xff, + 0x83, 0x39, 0x39, 0x39, 0x21, 0x33, 0x85, 0xff, + 0x03, 0x39, 0x39, 0x31, 0x07, 0x23, 0x31, 0xff, + 0x87, 0x33, 0x3f, 0x83, 0xf9, 0x39, 0x83, 0xff, + 0x81, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x83, 0xff, + 0x39, 0x39, 0x39, 0x11, 0x83, 0xc7, 0xef, 0xff, + 0x39, 0x39, 0x29, 0x01, 0x01, 0x11, 0x39, 0xff, + 0x39, 0x11, 0x83, 0xc7, 0x83, 0x11, 0x39, 0xff, + 0x99, 0x99, 0x99, 0xc3, 0xe7, 0xe7, 0xe7, 0xff, + 0x01, 0xf1, 0xe3, 0xc7, 0x8f, 0x1f, 0x01, 0xff, + 0xc3, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xc3, 0xff, + 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xff, + 0x87, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x87, 0xff, + 0xc7, 0x93, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x83, 0xf9, 0x81, 0x39, 0x81, 0xff, + 0x3f, 0x3f, 0x03, 0x39, 0x39, 0x39, 0x83, 0xff, + 0xff, 0xff, 0x81, 0x3f, 0x3f, 0x3f, 0x81, 0xff, + 0xf9, 0xf9, 0x81, 0x39, 0x39, 0x39, 0x81, 0xff, + 0xff, 0xff, 0x83, 0x39, 0x01, 0x3f, 0x83, 0xff, + 0xf1, 0xe7, 0x81, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, + 0xff, 0xff, 0x81, 0x39, 0x39, 0x81, 0xf9, 0x83, + 0x3f, 0x3f, 0x03, 0x39, 0x39, 0x39, 0x39, 0xff, + 0xe7, 0xff, 0xc7, 0xe7, 0xe7, 0xe7, 0x81, 0xff, + 0xf3, 0xff, 0xe3, 0xf3, 0xf3, 0xf3, 0xf3, 0x87, + 0x3f, 0x3f, 0x31, 0x03, 0x07, 0x23, 0x31, 0xff, + 0xc7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0x81, 0xff, + 0xff, 0xff, 0x03, 0x49, 0x49, 0x49, 0x49, 0xff, + 0xff, 0xff, 0x03, 0x39, 0x39, 0x39, 0x39, 0xff, + 0xff, 0xff, 0x83, 0x39, 0x39, 0x39, 0x83, 0xff, + 0xff, 0xff, 0x03, 0x39, 0x39, 0x03, 0x3f, 0x3f, + 0xff, 0xff, 0x81, 0x39, 0x39, 0x81, 0xf9, 0xf9, + 0xff, 0xff, 0x91, 0x8f, 0x9f, 0x9f, 0x9f, 0xff, + 0xff, 0xff, 0x83, 0x3f, 0x83, 0xf9, 0x03, 0xff, + 0xe7, 0xe7, 0x81, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, + 0xff, 0xff, 0x39, 0x39, 0x39, 0x39, 0x81, 0xff, + 0xff, 0xff, 0x99, 0x99, 0x99, 0xc3, 0xe7, 0xff, + 0xff, 0xff, 0x49, 0x49, 0x49, 0x49, 0x81, 0xff, + 0xff, 0xff, 0x39, 0x01, 0xc7, 0x01, 0x39, 0xff, + 0xff, 0xff, 0x39, 0x39, 0x39, 0x81, 0xf9, 0x83, + 0xff, 0xff, 0x01, 0xe3, 0xc7, 0x8f, 0x01, 0xff, + 0xf3, 0xe7, 0xe7, 0xcf, 0xe7, 0xe7, 0xf3, 0xff, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, + 0x9f, 0xcf, 0xcf, 0xe7, 0xcf, 0xcf, 0x9f, 0xff, + 0xff, 0xff, 0x8f, 0x45, 0xe3, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x93, 0x93, 0xff, + 0x83, 0x11, 0x29, 0x39, 0x29, 0x29, 0x83, 0xff, + 0x83, 0x31, 0x29, 0x31, 0x29, 0x31, 0x83, 0xff, + 0x83, 0x11, 0x11, 0x7d, 0x11, 0x11, 0x83, 0xff, + 0x83, 0x01, 0x01, 0x7d, 0x01, 0x01, 0x83, 0xff, + 0x83, 0x11, 0x21, 0x7d, 0x21, 0x11, 0x83, 0xff, + 0x83, 0x11, 0x09, 0x7d, 0x09, 0x11, 0x83, 0xff, + 0x83, 0x11, 0x39, 0x55, 0x11, 0x11, 0x83, 0xff, + 0x83, 0x11, 0x11, 0x55, 0x39, 0x11, 0x83, 0xff, + 0x83, 0x11, 0x39, 0x7d, 0x39, 0x11, 0x83, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe7, 0xff, 0xe7, 0xe7, 0xc7, 0xc7, 0xc7, 0xff, + 0xef, 0x83, 0x29, 0x2f, 0x29, 0x83, 0xef, 0xff, + 0xc3, 0x99, 0x9f, 0x03, 0x9f, 0x9f, 0x01, 0xff, + 0xff, 0xa5, 0xdb, 0xdb, 0xdb, 0xa5, 0xff, 0xff, + 0x99, 0x99, 0xc3, 0x81, 0xe7, 0x81, 0xe7, 0xff, + 0xe7, 0xe7, 0xe7, 0xff, 0xe7, 0xe7, 0xe7, 0xff, + 0xc3, 0x99, 0x87, 0xdb, 0xe1, 0x99, 0xc3, 0xff, + 0x93, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc3, 0xbd, 0x66, 0x5e, 0x5e, 0x66, 0xbd, 0xc3, + 0x87, 0xc3, 0x93, 0xc3, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc9, 0x93, 0x27, 0x93, 0xc9, 0xff, 0xff, + 0xff, 0xff, 0x81, 0xf9, 0xf9, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc3, 0xbd, 0x46, 0x5a, 0x46, 0x5a, 0xbd, 0xc3, + 0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xef, 0xd7, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe7, 0xe7, 0x81, 0xe7, 0xe7, 0xff, 0x81, 0xff, + 0xc7, 0xf3, 0xe7, 0xc3, 0xff, 0xff, 0xff, 0xff, + 0xc3, 0xe7, 0xf3, 0xc7, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x33, 0x33, 0x33, 0x33, 0x09, 0x3f, + 0xc1, 0x95, 0xb5, 0x95, 0xc1, 0xf5, 0xf5, 0xff, + 0xff, 0xff, 0xff, 0xcf, 0xcf, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xcf, + 0xe7, 0xc7, 0xe7, 0xc3, 0xff, 0xff, 0xff, 0xff, + 0xc7, 0x93, 0x93, 0xc7, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x27, 0x93, 0xc9, 0x93, 0x27, 0xff, 0xff, + 0xbd, 0x3b, 0xb7, 0xad, 0xd9, 0xb1, 0x7d, 0xff, + 0xbd, 0x3b, 0xb7, 0xa9, 0xdd, 0xbb, 0x71, 0xff, + 0x1d, 0xbb, 0xd7, 0x2d, 0xd9, 0xb1, 0x7d, 0xff, + 0xc7, 0xff, 0xc7, 0x9f, 0x39, 0x01, 0x83, 0xff, + 0xdf, 0xef, 0xc7, 0x93, 0x39, 0x01, 0x39, 0xff, + 0xf7, 0xef, 0xc7, 0x93, 0x39, 0x01, 0x39, 0xff, + 0xc7, 0x93, 0xc7, 0x93, 0x39, 0x01, 0x39, 0xff, + 0xcb, 0xa7, 0xc7, 0x93, 0x39, 0x01, 0x39, 0xff, + 0x93, 0xff, 0xc7, 0x93, 0x39, 0x01, 0x39, 0xff, + 0xef, 0xd7, 0xc7, 0x93, 0x39, 0x01, 0x39, 0xff, + 0xc1, 0x87, 0x27, 0x21, 0x07, 0x27, 0x21, 0xff, + 0xc3, 0x99, 0x3f, 0x3f, 0x99, 0xc3, 0xf7, 0xcf, + 0xdf, 0xef, 0x01, 0x3f, 0x03, 0x3f, 0x01, 0xff, + 0xf7, 0xef, 0x01, 0x3f, 0x03, 0x3f, 0x01, 0xff, + 0xc7, 0x93, 0x01, 0x3f, 0x03, 0x3f, 0x01, 0xff, + 0x93, 0xff, 0x01, 0x3f, 0x03, 0x3f, 0x01, 0xff, + 0xef, 0xf7, 0x81, 0xe7, 0xe7, 0xe7, 0x81, 0xff, + 0xf7, 0xef, 0x81, 0xe7, 0xe7, 0xe7, 0x81, 0xff, + 0xe7, 0xc3, 0x81, 0xe7, 0xe7, 0xe7, 0x81, 0xff, + 0x99, 0xff, 0x81, 0xe7, 0xe7, 0xe7, 0x81, 0xff, + 0x87, 0x93, 0x99, 0x09, 0x99, 0x93, 0x87, 0xff, + 0xcb, 0xa7, 0x19, 0x09, 0x01, 0x21, 0x31, 0xff, + 0xdf, 0xef, 0x83, 0x39, 0x39, 0x39, 0x83, 0xff, + 0xf7, 0xef, 0x83, 0x39, 0x39, 0x39, 0x83, 0xff, + 0xc7, 0x93, 0x83, 0x39, 0x39, 0x39, 0x83, 0xff, + 0xcb, 0xa7, 0x83, 0x39, 0x39, 0x39, 0x83, 0xff, + 0x93, 0xff, 0x83, 0x39, 0x39, 0x39, 0x83, 0xff, + 0xff, 0xbb, 0xd7, 0xef, 0xd7, 0xbb, 0xff, 0xff, + 0x83, 0x39, 0x31, 0x29, 0x19, 0x39, 0x83, 0xff, + 0xdf, 0xef, 0x39, 0x39, 0x39, 0x39, 0x83, 0xff, + 0xf7, 0xef, 0x39, 0x39, 0x39, 0x39, 0x83, 0xff, + 0xc7, 0x93, 0xff, 0x39, 0x39, 0x39, 0x83, 0xff, + 0x93, 0xff, 0x39, 0x39, 0x39, 0x39, 0x83, 0xff, + 0xf7, 0xef, 0x99, 0x99, 0xc3, 0xe7, 0xe7, 0xff, + 0x3f, 0x03, 0x39, 0x39, 0x39, 0x03, 0x3f, 0xff, + 0xc3, 0x99, 0x99, 0x93, 0x99, 0x89, 0x93, 0xff, + 0xdf, 0xef, 0x83, 0xf9, 0x81, 0x39, 0x81, 0xff, + 0xf7, 0xef, 0x83, 0xf9, 0x81, 0x39, 0x81, 0xff, + 0xc7, 0x93, 0x83, 0xf9, 0x81, 0x39, 0x81, 0xff, + 0xcb, 0xa7, 0x83, 0xf9, 0x81, 0x39, 0x81, 0xff, + 0x93, 0xff, 0x83, 0xf9, 0x81, 0x39, 0x81, 0xff, + 0xef, 0xd7, 0x83, 0xf9, 0x81, 0x39, 0x81, 0xff, + 0xff, 0xff, 0x83, 0xe9, 0x81, 0x2f, 0x83, 0xff, + 0xff, 0xff, 0x81, 0x3f, 0x3f, 0x81, 0xf7, 0xcf, + 0xdf, 0xef, 0x83, 0x39, 0x01, 0x3f, 0x83, 0xff, + 0xf7, 0xef, 0x83, 0x39, 0x01, 0x3f, 0x83, 0xff, + 0xc7, 0x93, 0x83, 0x39, 0x01, 0x3f, 0x83, 0xff, + 0x93, 0xff, 0x83, 0x39, 0x01, 0x3f, 0x83, 0xff, + 0xdf, 0xef, 0xff, 0xc7, 0xe7, 0xe7, 0x81, 0xff, + 0xf7, 0xef, 0xff, 0xc7, 0xe7, 0xe7, 0x81, 0xff, + 0xc7, 0x93, 0xff, 0xc7, 0xe7, 0xe7, 0x81, 0xff, + 0x93, 0xff, 0xc7, 0xe7, 0xe7, 0xe7, 0x81, 0xff, + 0x9b, 0x87, 0x67, 0x83, 0x39, 0x39, 0x83, 0xff, + 0xcb, 0xa7, 0x03, 0x39, 0x39, 0x39, 0x39, 0xff, + 0xdf, 0xef, 0x83, 0x39, 0x39, 0x39, 0x83, 0xff, + 0xf7, 0xef, 0x83, 0x39, 0x39, 0x39, 0x83, 0xff, + 0xc7, 0x93, 0x83, 0x39, 0x39, 0x39, 0x83, 0xff, + 0xcb, 0xa7, 0x83, 0x39, 0x39, 0x39, 0x83, 0xff, + 0x93, 0xff, 0x83, 0x39, 0x39, 0x39, 0x83, 0xff, + 0xff, 0xe7, 0xff, 0x81, 0xff, 0xe7, 0xff, 0xff, + 0xff, 0xff, 0x83, 0x31, 0x29, 0x19, 0x83, 0xff, + 0xdf, 0xef, 0x39, 0x39, 0x39, 0x39, 0x81, 0xff, + 0xf7, 0xef, 0x39, 0x39, 0x39, 0x39, 0x81, 0xff, + 0xc7, 0x93, 0xff, 0x39, 0x39, 0x39, 0x81, 0xff, + 0x93, 0xff, 0x39, 0x39, 0x39, 0x39, 0x81, 0xff, + 0xf7, 0xef, 0x39, 0x39, 0x39, 0x81, 0xf9, 0x83, + 0x3f, 0x3f, 0x03, 0x39, 0x39, 0x03, 0x3f, 0x3f, + 0x93, 0xff, 0x39, 0x39, 0x39, 0x81, 0xf9, 0x83, +}; diff --git a/src/cart/api.zig b/src/cart/api.zig index eeba229..0cd5cfb 100644 --- a/src/cart/api.zig +++ b/src/cart/api.zig @@ -35,9 +35,13 @@ pub const DisplayColor = packed struct(u16) { none = -1, _, - inline fn from(color: ?DisplayColor) Optional { + pub fn from(color: ?DisplayColor) Optional { return if (color) |c| @enumFromInt(@as(u16, @bitCast(c))) else .none; } + + pub fn unwrap(opt: Optional) ?DisplayColor { + return if (opt == .none) null else @bitCast(@as(u16, @truncate(@as(u32, @intCast(@intFromEnum(opt)))))); + } }; };