basic title screen i guess lol
Signed-off-by: Xe Iaso <me@christine.website>
This commit is contained in:
parent
56cde0fcf6
commit
a1be32b5c6
117
src/main.zig
117
src/main.zig
|
@ -1,25 +1,110 @@
|
|||
const w4 = @import("wasm4.zig");
|
||||
const sh0rk = @import("sh0rk.zig");
|
||||
const sprites = @import("sprites.zig");
|
||||
|
||||
const smiley = [8]u8{
|
||||
0b11000011,
|
||||
0b10000001,
|
||||
0b00100100,
|
||||
0b00100100,
|
||||
0b00000000,
|
||||
0b00100100,
|
||||
0b10011001,
|
||||
0b11000011,
|
||||
};
|
||||
const Direction = sh0rk.Direction;
|
||||
const Point = sh0rk.Point;
|
||||
const Rect = sh0rk.Rect;
|
||||
|
||||
var frame_count: u32 = 0;
|
||||
var mara_direction: Direction = Direction.Right;
|
||||
var mara_frame: bool = false;
|
||||
var mara_box: Rect = Rect{.base = Point{.x = 60, .y = 60}, .width = 16, .height = 16};
|
||||
var mara_speed: i32 = 0;
|
||||
var screen = Rect{.base = Point{.x = 0, .y = 0}, .width = 160, .height = 160};
|
||||
|
||||
export fn start() void {
|
||||
w4.m.palette.* = .{
|
||||
w4.Color{.blue = 0xAF, .green = 0xB0, .red = 0xD9},
|
||||
//0xD9B0AF,
|
||||
w4.Color{.blue = 0x83, .green = 0x63, .red = 0xAA},
|
||||
//0xAA6383,
|
||||
w4.Color{.blue = 0x83, .green = 0x3C, .red = 0xAA},
|
||||
//0x6A3C4F,
|
||||
w4.Color{.blue = 0x2D, .green = 0x23, .red = 0x36},
|
||||
//0x36232D,
|
||||
};
|
||||
}
|
||||
|
||||
export fn update() void {
|
||||
w4.DRAW_COLORS.* = 2;
|
||||
w4.text("Hello from Zig!", 10, 10);
|
||||
w4.m.colors._0 = .p3;
|
||||
w4.m.colors._1 = .p0;
|
||||
w4.text("Mara 2:\nTamamo's Fury", 10, 10);
|
||||
|
||||
const gamepad = w4.GAMEPAD1.*;
|
||||
if (gamepad & w4.BUTTON_1 != 0) {
|
||||
w4.DRAW_COLORS.* = 4;
|
||||
const gamepad = w4.m.gamepads[0];
|
||||
if (gamepad.a) {
|
||||
w4.m.colors._0 = .p2;
|
||||
}
|
||||
|
||||
mara_speed = 0;
|
||||
if (gamepad.up) {
|
||||
mara_direction = Direction.Up;
|
||||
mara_speed = 2;
|
||||
} else if (gamepad.down) {
|
||||
mara_direction = Direction.Down;
|
||||
mara_speed = 2;
|
||||
} else if (gamepad.left) {
|
||||
mara_direction = Direction.Left;
|
||||
mara_speed = 2;
|
||||
} else if (gamepad.right) {
|
||||
mara_direction = Direction.Right;
|
||||
mara_speed = 2;
|
||||
}
|
||||
|
||||
switch (mara_direction) {
|
||||
.Up => {
|
||||
mara_box.base.y -= mara_speed;
|
||||
},
|
||||
.Down => {
|
||||
mara_box.base.y += mara_speed;
|
||||
},
|
||||
.Left => {
|
||||
mara_box.base.x -= mara_speed;
|
||||
},
|
||||
.Right => {
|
||||
mara_box.base.x += mara_speed;
|
||||
},
|
||||
}
|
||||
|
||||
if (mara_box.base.x < 0) {
|
||||
mara_box.base.x = 0;
|
||||
} else if (mara_box.base.x > 160 - mara_box.width) {
|
||||
mara_box.base.x = 160 - mara_box.width;
|
||||
}
|
||||
if (mara_box.base.y < 0) {
|
||||
mara_box.base.y = 0;
|
||||
} else if (mara_box.base.y > 160 - mara_box.height) {
|
||||
mara_box.base.y = 160 - mara_box.height;
|
||||
}
|
||||
|
||||
w4.blit(&smiley, 76, 76, 8, 8, w4.BLIT_1BPP);
|
||||
w4.text("Press X to blink", 16, 90);
|
||||
|
||||
w4.m.colors._0 = .transparent;
|
||||
w4.m.colors._1 = .p0;
|
||||
w4.m.colors._2 = .p1;
|
||||
w4.m.colors._3 = .p3;
|
||||
|
||||
var flags: w4.BlitFlags = w4.BlitFlags {
|
||||
.two_bits = true,
|
||||
};
|
||||
|
||||
if (mara_direction == Direction.Left) {
|
||||
flags.flip_x = true;
|
||||
}
|
||||
|
||||
if (frame_count % 15 == 0 and mara_speed > 0) {
|
||||
mara_frame = !mara_frame;
|
||||
}
|
||||
var frame: u32 = switch (mara_direction) {
|
||||
.Left => 4,
|
||||
.Right => 4,
|
||||
.Up => 2,
|
||||
.Down => 0,
|
||||
};
|
||||
var step: u32 = if (mara_frame) 1 else 0;
|
||||
|
||||
w4.blitSub(&sprites.Mara, @intCast(u32, mara_box.base.x), @intCast(u32, mara_box.base.y), 16, 16, 16 * (frame + step), 0, 96, flags);
|
||||
|
||||
frame_count += 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
pub const Point = packed struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
pub fn init(x: i32, y: i32) @This() {
|
||||
return @This() {
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn equals(this: @This(), other: @This()) bool {
|
||||
return this.x == other.x and this.y == other.y;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Rect = packed struct {
|
||||
base: Point,
|
||||
width: i32,
|
||||
height: i32,
|
||||
pub fn init(base: Point, width: i32, height: i32) @This() {
|
||||
return @This() {
|
||||
.base = base,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn inside(this: @This(), point: Point) bool {
|
||||
return point.x >= this.base.x and point.x < this.base.x + this.width and point.y >= this.base.y and point.y < this.base.y + this.height;
|
||||
}
|
||||
|
||||
pub fn collides(this: @This(), other: @This()) bool {
|
||||
return this.base.x < other.base.x + other.width and this.base.x + this.width > other.base.x and this.base.y < other.base.y + other.height and this.base.y + this.height > other.base.y;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Direction = enum(u2) {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// Mara
|
||||
pub const Mara_width = 96;
|
||||
pub const Mara_height = 16;
|
||||
pub const Mara_flags = 1; // BLIT_2BPP
|
||||
pub const Mara = [384]u8{ 0x3f,0x00,0x00,0xfc,0x3f,0x00,0x00,0xfc,0x3f,0x00,0x00,0xfc,0x3f,0x00,0x00,0xfc,0x00,0x00,0xf0,0x00,0x00,0x00,0xf0,0x00,0x36,0xff,0xc3,0x9c,0x36,0xff,0xc3,0x9c,0x3a,0xc3,0xff,0xac,0x3a,0xc3,0xff,0xac,0x00,0x00,0xec,0x00,0x00,0x00,0xec,0x00,0x35,0xd5,0xbe,0x5c,0x35,0xd6,0xbe,0x5c,0x3a,0xbf,0xab,0xac,0x3a,0xbf,0xab,0xac,0x30,0x00,0xeb,0x00,0x30,0x00,0xeb,0x00,0x3a,0xd6,0x56,0xac,0x3a,0xd9,0x56,0xac,0x3a,0xe6,0x66,0xec,0x3a,0xe6,0x66,0xec,0xdc,0x03,0xe9,0xf0,0xdc,0x03,0xe9,0xf0,0x0f,0x59,0x5e,0xf0,0x0f,0x65,0x5e,0xf0,0x0f,0xb9,0x9d,0xf0,0x0f,0xb9,0x9d,0xf0,0xe7,0x0e,0x65,0x5c,0xe7,0x0e,0x65,0x5c,0x03,0x65,0x5e,0xc0,0x03,0xb5,0x5e,0xc0,0x03,0xde,0x77,0xc0,0x03,0xde,0x77,0xc0,0xe7,0x0d,0xa7,0x5c,0xe7,0x0d,0xa7,0x5c,0x03,0xd7,0xd6,0xc0,0x03,0xd7,0xd6,0xc0,0x03,0xe7,0xdb,0xc0,0x03,0xe7,0xdb,0xc0,0xe9,0xcd,0xa7,0x5c,0xe9,0xcd,0xa7,0x5c,0x00,0xe5,0x5b,0x00,0x00,0xe5,0x5b,0x00,0x00,0xe9,0x6b,0x00,0x00,0xe9,0x6b,0x00,0x3a,0x7d,0xa5,0x7c,0x3a,0x7d,0xa5,0x7c,0x03,0xff,0xff,0xc0,0x03,0xff,0xff,0xc0,0x03,0xfa,0xaf,0xc0,0x03,0xfa,0xaf,0xc0,0x3a,0xc3,0xe9,0xf0,0x3a,0xc3,0xe9,0xf0,0x0d,0xaa,0xaa,0x70,0x0d,0xaa,0xaa,0x70,0x0d,0xae,0xba,0x70,0x0d,0xae,0xba,0x70,0x3b,0x00,0xff,0xc0,0x3b,0x00,0xff,0xc0,0x0d,0xea,0xab,0x70,0x0d,0xea,0xab,0x70,0x0d,0xee,0xbb,0x70,0x0d,0xee,0xbb,0x70,0xeb,0x03,0xb7,0xb0,0xeb,0x03,0xb7,0xb0,0x0d,0xea,0xab,0x70,0x0d,0xea,0xab,0x70,0x0d,0xee,0xbb,0x70,0x0d,0xee,0xbb,0x70,0xea,0xff,0xde,0xb0,0xea,0xff,0xad,0xf0,0x03,0x37,0xdc,0xc0,0x03,0x37,0xdc,0xc0,0x03,0x3e,0xbc,0xc0,0x03,0x3e,0xbc,0xc0,0x3a,0xaa,0xfa,0xb0,0x3a,0xaa,0xab,0xb0,0x00,0x37,0xdc,0x00,0x00,0x37,0xdc,0x00,0x00,0x3f,0xfc,0x00,0x00,0x3f,0xfc,0x00,0x3a,0xaf,0xd5,0xf0,0x3a,0xaf,0xd5,0xf0,0x00,0x37,0x30,0x00,0x00,0x0c,0xdc,0x00,0x00,0x37,0x30,0x00,0x00,0x0c,0xdc,0x00,0x0f,0xf0,0x37,0x00,0x0f,0xf0,0x37,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x03,0x8c,0xb0,0x00,0x00,0xee,0xc0 };
|
||||
|
||||
|
260
src/wasm4.zig
260
src/wasm4.zig
|
@ -1,13 +1,25 @@
|
|||
//
|
||||
// WASM-4: https://wasm4.org/docs
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
fn assert_equal(a: anytype, b: anytype, comptime error_msg: []const u8) void {
|
||||
if (a != b) @compileError(std.fmt.comptimePrint("{} != {} {s}", .{a, b, error_msg}));
|
||||
}
|
||||
|
||||
comptime {
|
||||
const builtin = @import("builtin");
|
||||
const native_endian = builtin.target.cpu.arch.endian();
|
||||
assert_equal(native_endian, .Little, "Bit flags need little endian");
|
||||
}
|
||||
|
||||
// ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
// │ │
|
||||
// │ Platform Constants │
|
||||
// │ │
|
||||
// └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
pub const CANVAS_SIZE: u32 = 160;
|
||||
pub const SCREEN_SIZE: u32 = 160;
|
||||
|
||||
// ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
// │ │
|
||||
|
@ -15,31 +27,99 @@ pub const CANVAS_SIZE: u32 = 160;
|
|||
// │ │
|
||||
// └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
pub const PALETTE: *[4]u32 = @intToPtr(*[4]u32, 0x04);
|
||||
pub const DRAW_COLORS: *u16 = @intToPtr(*u16, 0x14);
|
||||
pub const GAMEPAD1: *const u8 = @intToPtr(*const u8, 0x16);
|
||||
pub const GAMEPAD2: *const u8 = @intToPtr(*const u8, 0x17);
|
||||
pub const GAMEPAD3: *const u8 = @intToPtr(*const u8, 0x18);
|
||||
pub const GAMEPAD4: *const u8 = @intToPtr(*const u8, 0x19);
|
||||
pub const MOUSE_X: *const i16 = @intToPtr(*const i16, 0x1a);
|
||||
pub const MOUSE_Y: *const i16 = @intToPtr(*const i16, 0x1c);
|
||||
pub const MOUSE_BUTTONS: *const u8 = @intToPtr(*const u8, 0x1e);
|
||||
pub const SYSTEM_FLAGS: *u8 = @intToPtr(*u8, 0x1f);
|
||||
pub const FRAMEBUFFER: *[6400]u8 = @intToPtr(*[6400]u8, 0xA0);
|
||||
pub const Memory = packed struct {
|
||||
_padding: [4]u8,
|
||||
palette: [4]Color,
|
||||
colors: DrawColors,
|
||||
gamepads: [4]GamePad,
|
||||
mouse: Mouse,
|
||||
system: SystemFlags,
|
||||
_reserved: [128]u8,
|
||||
framebuffer: [6400]u8,
|
||||
userdata: [58976]u8,
|
||||
};
|
||||
|
||||
pub const BUTTON_1: u8 = 1;
|
||||
pub const BUTTON_2: u8 = 2;
|
||||
pub const BUTTON_LEFT: u8 = 16;
|
||||
pub const BUTTON_RIGHT: u8 = 32;
|
||||
pub const BUTTON_UP: u8 = 64;
|
||||
pub const BUTTON_DOWN: u8 = 128;
|
||||
comptime {
|
||||
assert_equal(@bitSizeOf(Memory), 64 * 1024 * 8, "Memory layout wrong");
|
||||
}
|
||||
|
||||
pub const MOUSE_LEFT: u8 = 1;
|
||||
pub const MOUSE_RIGHT: u8 = 2;
|
||||
pub const MOUSE_MIDDLE: u8 = 4;
|
||||
const dummym: Memory = undefined;
|
||||
|
||||
pub const SYSTEM_PRESERVE_FRAMEBUFFER: u8 = 1;
|
||||
pub const SYSTEM_HIDE_GAMEPAD_OVERLAY: u8 = 2;
|
||||
pub const m = struct {
|
||||
pub const palette = @intToPtr(*@TypeOf(dummym.palette ), 0 + @offsetOf(Memory, "palette" ));
|
||||
pub const colors = @intToPtr(*@TypeOf(dummym.colors ), 0 + @offsetOf(Memory, "colors" ));
|
||||
pub const gamepads = @intToPtr(*@TypeOf(dummym.gamepads ), 0 + @offsetOf(Memory, "gamepads" ));
|
||||
pub const mouse = @intToPtr(*@TypeOf(dummym.mouse ), 0 + @offsetOf(Memory, "mouse" ));
|
||||
pub const system = @intToPtr(*@TypeOf(dummym.system ), 0 + @offsetOf(Memory, "system" ));
|
||||
pub const framebuffer = @intToPtr(*@TypeOf(dummym.framebuffer), 0 + @offsetOf(Memory, "framebuffer"));
|
||||
pub const userdata = @intToPtr(*@TypeOf(dummym.userdata ), 0 + @offsetOf(Memory, "userdata" ));
|
||||
};
|
||||
|
||||
pub const Color = packed struct {
|
||||
blue : u8,
|
||||
green : u8,
|
||||
red : u8,
|
||||
_reserved: u8 = 0,
|
||||
};
|
||||
|
||||
pub const DrawColors = packed struct {
|
||||
_0: ColorIndex,
|
||||
_1: ColorIndex,
|
||||
_2: ColorIndex,
|
||||
_3: ColorIndex,
|
||||
};
|
||||
|
||||
pub const ColorIndex = enum(u4) {
|
||||
transparent = 0,
|
||||
/// Use palette[0]
|
||||
p0 = 1,
|
||||
/// Use palette[1]
|
||||
p1 = 2,
|
||||
/// Use palette[2]
|
||||
p2 = 3,
|
||||
/// Use palette[3]
|
||||
p3 = 4,
|
||||
};
|
||||
|
||||
pub const GamePad = packed struct {
|
||||
a: bool,
|
||||
b: bool,
|
||||
_reserved: u2,
|
||||
left: bool,
|
||||
right: bool,
|
||||
up: bool,
|
||||
down: bool,
|
||||
};
|
||||
|
||||
pub const Mouse = packed struct {
|
||||
x: i16,
|
||||
y: i16,
|
||||
/// primary button
|
||||
b0: bool,
|
||||
/// secondary button
|
||||
b1: bool,
|
||||
/// third button
|
||||
b2: bool,
|
||||
_reserved: u5,
|
||||
};
|
||||
|
||||
pub const SystemFlags = packed struct {
|
||||
preserve_framebuffer: bool,
|
||||
hide_gamepad_overlay: bool,
|
||||
_reserved: u6,
|
||||
};
|
||||
|
||||
// ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
// │ │
|
||||
// │ Raw Functions │
|
||||
// │ │
|
||||
// └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
const raw_api = struct {
|
||||
extern fn blit(sprite: [*]const u8, x: u32, y: u32, width: u32, height: u32, flags: u32) void;
|
||||
extern fn blitSub(sprite: [*]const u8, x: u32, y: u32, width: u32, height: u32, src_x: u32, src_y: u32, stride: u32, flags: u32) void;
|
||||
extern fn tone(frequency: u32, duration: u32, volume: u32, flags: u32) void;
|
||||
};
|
||||
|
||||
// ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
// │ │
|
||||
|
@ -47,38 +127,49 @@ pub const SYSTEM_HIDE_GAMEPAD_OVERLAY: u8 = 2;
|
|||
// │ │
|
||||
// └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
pub const BlitFlags = packed struct {
|
||||
/// one or two bits per pixel
|
||||
two_bits: bool = false,
|
||||
flip_x: bool = false,
|
||||
flip_y: bool = false,
|
||||
rotate: bool = false,
|
||||
_reserved: u28 = 0,
|
||||
};
|
||||
|
||||
/// Copies pixels to the framebuffer.
|
||||
pub extern fn blit(sprite: [*]const u8, x: i32, y: i32, width: i32, height: i32, flags: u32) void;
|
||||
pub fn blit(sprite: []const u8, x: u32, y: u32, width: u32, height: u32, flags: BlitFlags) void {
|
||||
|
||||
raw_api.blit(sprite.ptr, x, y, width, height, @bitCast(u32, flags));
|
||||
}
|
||||
|
||||
/// Copies a subregion within a larger sprite atlas to the framebuffer.
|
||||
pub extern fn blitSub(sprite: [*]const u8, x: i32, y: i32, width: i32, height: i32, src_x: u32, src_y: u32, stride: i32, flags: u32) void;
|
||||
|
||||
pub const BLIT_2BPP: u32 = 1;
|
||||
pub const BLIT_1BPP: u32 = 0;
|
||||
pub const BLIT_FLIP_X: u32 = 2;
|
||||
pub const BLIT_FLIP_Y: u32 = 4;
|
||||
pub const BLIT_ROTATE: u32 = 8;
|
||||
/// srcX: Source X position of the sprite region.
|
||||
/// srcY: Source Y position of the sprite region.
|
||||
/// stride: Total width of the overall sprite atlas. This is typically larger than width.
|
||||
pub fn blitSub(sprite: []const u8, x: u32, y: u32, width: u32, height: u32, src_x: u32, src_y: u32, stride: u32, flags: BlitFlags) void {
|
||||
raw_api.blitSub(sprite.ptr, x, y, width, height, src_x, src_y, stride, @bitCast(u32, flags));
|
||||
}
|
||||
|
||||
/// Draws a line between two points.
|
||||
pub extern fn line(x1: i32, y1: i32, x2: i32, y2: i32) void;
|
||||
pub extern fn line(x1: u32, y1: u32, x2: u32, y2: u32) void;
|
||||
|
||||
/// Draws an oval (or circle).
|
||||
pub extern fn oval(x: i32, y: i32, width: i32, height: i32) void;
|
||||
pub extern fn oval(x: u32, y: u32, width: u32, height: u32) void;
|
||||
|
||||
/// Draws a rectangle.
|
||||
pub extern fn rect(x: i32, y: i32, width: u32, height: u32) void;
|
||||
pub extern fn rect(x: u32, y: u32, width: u32, height: u32) void;
|
||||
|
||||
/// Draws text using the built-in system font.
|
||||
pub fn text(str: []const u8, x: i32, y: i32) void {
|
||||
pub fn text(str: []const u8, x: u32, y: u32) void {
|
||||
textUtf8(str.ptr, str.len, x, y);
|
||||
}
|
||||
extern fn textUtf8(strPtr: [*]const u8, strLen: usize, x: i32, y: i32) void;
|
||||
extern fn textUtf8(strPtr: [*]const u8, strLen: usize, x: u32, y: u32) void;
|
||||
|
||||
/// Draws a vertical line
|
||||
pub extern fn vline(x: i32, y: i32, len: u32) void;
|
||||
pub extern fn vline(x: u32, y: u32, len: u32) void;
|
||||
|
||||
/// Draws a horizontal line
|
||||
pub extern fn hline(x: i32, y: i32, len: u32) void;
|
||||
pub extern fn hline(x: u32, y: u32, len: u32) void;
|
||||
|
||||
// ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
// │ │
|
||||
|
@ -87,16 +178,81 @@ pub extern fn hline(x: i32, y: i32, len: u32) void;
|
|||
// └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
/// Plays a sound tone.
|
||||
pub extern fn tone(frequency: u32, duration: u32, volume: u32, flags: u32) void;
|
||||
/// frequency: Wave frequency in hertz.
|
||||
/// duration: Duration of the tone in frames (1/60th of a second), up to 255 frames.
|
||||
/// volume: Volume of the sustain and attack durations, between 0 and 100.
|
||||
pub fn tone(frequency: Tone.Frequency, duration: Tone.Duration, volume: Tone.Volume, flags: Tone.Flags) void {
|
||||
std.debug.assert(volume.is_valid());
|
||||
tone(@bitCast(u32, frequency), @bitCast(u32, duration), @bitCast(u32, volume), @bitCast(u32, flags));
|
||||
}
|
||||
|
||||
pub const TONE_PULSE1: u32 = 0;
|
||||
pub const TONE_PULSE2: u32 = 1;
|
||||
pub const TONE_TRIANGLE: u32 = 2;
|
||||
pub const TONE_NOISE: u32 = 3;
|
||||
pub const TONE_MODE1: u32 = 0;
|
||||
pub const TONE_MODE2: u32 = 4;
|
||||
pub const TONE_MODE3: u32 = 8;
|
||||
pub const TONE_MODE4: u32 = 12;
|
||||
pub const Tone = struct {
|
||||
/// Wave frequency in hertz.
|
||||
pub const Frequency = packed struct {
|
||||
start: u16,
|
||||
end: u16 = 0,
|
||||
};
|
||||
|
||||
/// Duration of ADSR of note (unit: frames)
|
||||
///
|
||||
/// ^
|
||||
/// / \ decay
|
||||
/// attack / \
|
||||
/// / \--------
|
||||
/// / sustain \ release
|
||||
/// / \
|
||||
pub const Duration = packed struct {
|
||||
sustain : u8 = 0,
|
||||
release : u8 = 0,
|
||||
decay : u8 = 0,
|
||||
attack : u8 = 0,
|
||||
};
|
||||
|
||||
/// Volume of note (0 to 100)
|
||||
///
|
||||
/// ^ <-- attack volume
|
||||
/// / \
|
||||
/// / \
|
||||
/// / \-------- <-- sustain valume
|
||||
/// / \
|
||||
/// / \
|
||||
pub const Volume = packed struct {
|
||||
sustain : u8,
|
||||
attack : u8 = 100,
|
||||
|
||||
pub fn is_valid(volume: @This()) bool {
|
||||
return (0 <= volume.sustain) and (volume.sustain <= 100)
|
||||
and (0 <= volume.attack ) and (volume.attack <= 100);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Flags = packed struct {
|
||||
channel: Channel,
|
||||
pulse_duty: DutyCycle = 2,
|
||||
pan: Pan = .both,
|
||||
};
|
||||
|
||||
pub const Channel = enum(u2) {
|
||||
pulse0 = 0,
|
||||
pulse1 = 1,
|
||||
triangle = 2,
|
||||
noise = 3,
|
||||
};
|
||||
|
||||
pub const DutyCycle = enum(u2) {
|
||||
@"1/8" = 0,
|
||||
@"1/4" = 1,
|
||||
@"1/2" = 2,
|
||||
};
|
||||
|
||||
/// Which stereo channel(s) to play audio in
|
||||
pub const Pan = enum(u2) {
|
||||
/// play audio in both stereo channels
|
||||
both = 0,
|
||||
left = 1,
|
||||
right = 2,
|
||||
};
|
||||
};
|
||||
|
||||
// ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
// │ │
|
||||
|
@ -121,13 +277,3 @@ pub fn trace(x: []const u8) void {
|
|||
traceUtf8(x.ptr, x.len);
|
||||
}
|
||||
extern fn traceUtf8(strPtr: [*]const u8, strLen: usize) void;
|
||||
|
||||
/// Use with caution, as there's no compile-time type checking.
|
||||
///
|
||||
/// * %c, %d, and %x expect 32-bit integers.
|
||||
/// * %f expects 64-bit floats.
|
||||
/// * %s expects a *zero-terminated* string pointer.
|
||||
///
|
||||
/// See https://github.com/aduros/wasm4/issues/244 for discussion and type-safe
|
||||
/// alternatives.
|
||||
pub extern fn tracef(x: [*:0]const u8, ...) void;
|
||||
|
|
Loading…
Reference in New Issue