1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
//
// WASM-4: https://wasm4.org/docs

#![no_std]

// ┌───────────────────────────────────────────────────────────────────────────┐
// │                                                                           │
// │ Platform Constants                                                        │
// │                                                                           │
// └───────────────────────────────────────────────────────────────────────────┘

pub const SCREEN_SIZE: u32 = 160;

// ┌───────────────────────────────────────────────────────────────────────────┐
// │                                                                           │
// │ Memory Addresses                                                          │
// │                                                                           │
// └───────────────────────────────────────────────────────────────────────────┘

pub const PALETTE: *mut [u32; 4] = 0x04 as *mut [u32; 4];
pub const DRAW_COLORS: *mut u16 = 0x14 as *mut u16;
pub const GAMEPAD1: *const u8 = 0x16 as *const u8;
pub const GAMEPAD2: *const u8 = 0x17 as *const u8;
pub const GAMEPAD3: *const u8 = 0x18 as *const u8;
pub const GAMEPAD4: *const u8 = 0x19 as *const u8;
pub const MOUSE_X: *const i16 = 0x1a as *const i16;
pub const MOUSE_Y: *const i16 = 0x1c as *const i16;
pub const MOUSE_BUTTONS: *const u8 = 0x1e as *const u8;
pub const SYSTEM_FLAGS: *mut u8 = 0x1f as *mut u8;
pub const NETPLAY: *const u8 = 0x20 as *const u8;
pub const FRAMEBUFFER: *mut [u8; 6400] = 0xa0 as *mut [u8; 6400];

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;

pub const MOUSE_LEFT: u8 = 1;
pub const MOUSE_RIGHT: u8 = 2;
pub const MOUSE_MIDDLE: u8 = 4;

pub const SYSTEM_PRESERVE_FRAMEBUFFER: u8 = 1;
pub const SYSTEM_HIDE_GAMEPAD_OVERLAY: u8 = 2;

// ┌───────────────────────────────────────────────────────────────────────────┐
// │                                                                           │
// │ Drawing Functions                                                         │
// │                                                                           │
// └───────────────────────────────────────────────────────────────────────────┘

/// Copies pixels to the framebuffer.
pub fn blit(sprite: &[u8], x: i32, y: i32, width: u32, height: u32, flags: u32) {
    unsafe { extern_blit(sprite.as_ptr(), x, y, width, height, flags) }
}
extern "C" {
    #[link_name = "blit"]
    fn extern_blit(sprite: *const u8, x: i32, y: i32, width: u32, height: u32, flags: u32);
}

/// Copies a subregion within a larger sprite atlas to the framebuffer.
#[allow(clippy::too_many_arguments)]
pub fn blit_sub(
    sprite: &[u8],
    x: i32,
    y: i32,
    width: u32,
    height: u32,
    src_x: u32,
    src_y: u32,
    stride: u32,
    flags: u32,
) {
    unsafe {
        extern_blit_sub(
            sprite.as_ptr(),
            x,
            y,
            width,
            height,
            src_x,
            src_y,
            stride,
            flags,
        )
    }
}
extern "C" {
    #[link_name = "blitSub"]
    fn extern_blit_sub(
        sprite: *const u8,
        x: i32,
        y: i32,
        width: u32,
        height: u32,
        src_x: u32,
        src_y: u32,
        stride: u32,
        flags: u32,
    );
}

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;

/// Draws a line between two points.
pub fn line(x1: i32, y1: i32, x2: i32, y2: i32) {
    unsafe { extern_line(x1, y1, x2, y2) }
}
extern "C" {
    #[link_name = "line"]
    fn extern_line(x1: i32, y1: i32, x2: i32, y2: i32);
}

/// Draws an oval (or circle).
pub fn oval(x: i32, y: i32, width: u32, height: u32) {
    unsafe { extern_oval(x, y, width, height) }
}
extern "C" {
    #[link_name = "oval"]
    fn extern_oval(x: i32, y: i32, width: u32, height: u32);
}

/// Draws a rectangle.
pub fn rect(x: i32, y: i32, width: u32, height: u32) {
    unsafe { extern_rect(x, y, width, height) }
}
extern "C" {
    #[link_name = "rect"]
    fn extern_rect(x: i32, y: i32, width: u32, height: u32);
}

/// Draws text using the built-in system font.
pub fn text<T: AsRef<[u8]>>(text: T, x: i32, y: i32) {
    let text_ref = text.as_ref();
    unsafe { extern_text(text_ref.as_ptr(), text_ref.len(), x, y) }
}
extern "C" {
    #[link_name = "textUtf8"]
    fn extern_text(text: *const u8, length: usize, x: i32, y: i32);
}

/// Draws a vertical line
pub fn vline(x: i32, y: i32, len: u32) {
    unsafe {
        extern_vline(x, y, len);
    }
}

extern "C" {
    #[link_name = "vline"]
    fn extern_vline(x: i32, y: i32, len: u32);
}

/// Draws a horizontal line
pub fn hline(x: i32, y: i32, len: u32) {
    unsafe {
        extern_hline(x, y, len);
    }
}

extern "C" {
    #[link_name = "hline"]
    fn extern_hline(x: i32, y: i32, len: u32);
}

// ┌───────────────────────────────────────────────────────────────────────────┐
// │                                                                           │
// │ Sound Functions                                                           │
// │                                                                           │
// └───────────────────────────────────────────────────────────────────────────┘

/// Plays a sound tone.
pub fn tone(frequency: u32, duration: u32, volume: u32, flags: u32) {
    unsafe { extern_tone(frequency, duration, volume, flags) }
}
extern "C" {
    #[link_name = "tone"]
    fn extern_tone(frequency: u32, duration: u32, volume: u32, flags: u32);
}

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_PAN_LEFT: u32 = 16;
pub const TONE_PAN_RIGHT: u32 = 32;

// ┌───────────────────────────────────────────────────────────────────────────┐
// │                                                                           │
// │ Storage Functions                                                         │
// │                                                                           │
// └───────────────────────────────────────────────────────────────────────────┘

extern "C" {
    /// Reads up to `size` bytes from persistent storage into the pointer `dest`.
    pub fn diskr(dest: *mut u8, size: u32) -> u32;

    /// Writes up to `size` bytes from the pointer `src` into persistent storage.
    pub fn diskw(src: *const u8, size: u32) -> u32;
}

// ┌───────────────────────────────────────────────────────────────────────────┐
// │                                                                           │
// │ Other Functions                                                           │
// │                                                                           │
// └───────────────────────────────────────────────────────────────────────────┘

/// Prints a message to the debug console.
pub fn trace<T: AsRef<str>>(text: T) {
    let text_ref = text.as_ref();
    unsafe { extern_trace(text_ref.as_ptr(), text_ref.len()) }
}
extern "C" {
    #[link_name = "traceUtf8"]
    fn extern_trace(trace: *const u8, length: usize);
}