mirror of
https://github.com/exoticorn/microw8.git
synced 2026-01-20 19:26:43 +01:00
Compare commits
5 Commits
efbc5f19f5
...
35aeebd0b6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35aeebd0b6 | ||
| fb3fd5e8bb | |||
| b85f96b0bb | |||
| b69055b58d | |||
|
|
937ccf60c9 |
1149
Cargo.lock
generated
1149
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "uw8"
|
name = "uw8"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
@@ -11,7 +11,7 @@ native = ["wasmtime", "uw8-window", "cpal", "rubato" ]
|
|||||||
browser = ["warp", "tokio", "tokio-stream", "webbrowser"]
|
browser = ["warp", "tokio", "tokio-stream", "webbrowser"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmtime = { version = "19.0.1", optional = true }
|
wasmtime = { git = "https://github.com/bytecodealliance/wasmtime.git", rev = "0f48f939b9870036562ca02ff21253547a9f1a5c", optional = true }
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
env_logger = "0.11.3"
|
env_logger = "0.11.3"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ include "../include/microw8-api.cwa"
|
|||||||
export fn upd() {
|
export fn upd() {
|
||||||
let i: i32;
|
let i: i32;
|
||||||
loop pixels {
|
loop pixels {
|
||||||
let inline t = time() * 63 as f32;
|
let inline t = 16!56;
|
||||||
let lazy x = (i % 320 - 160) as f32;
|
let inline x = (i % 320 - 160) as f32;
|
||||||
let lazy y = (i / 320 - 120) as f32;
|
let inline y = (i #/ 320 - 120) as f32;
|
||||||
let inline d = 40000 as f32 / sqrt(x * x + y * y);
|
let inline d = 0xa000 as f32 / sqrt(x * x + y * y);
|
||||||
let inline u = atan2(x, y) * (512.0 / 3.141);
|
let inline a = atan2(x, y) * 163_f; // (512 / pi)
|
||||||
let inline c = ((i32.trunc_sat_f32_s(d + t * 2 as f32) ^ i32.trunc_sat_f32_s(u + t)) & 255) >> 4;
|
let inline u = i32.trunc_sat_f32_s(a) + t;
|
||||||
|
let inline v = i32.trunc_sat_f32_s(d) + t * 2;
|
||||||
|
let inline c = ((v ^ u) #/ 16) % 16;
|
||||||
i?FRAMEBUFFER = c;
|
i?FRAMEBUFFER = c;
|
||||||
|
|
||||||
branch_if (i := i + 1) < 320*240: pixels;
|
branch_if (i := i + 1) < 320*240: pixels;
|
||||||
|
|||||||
6
examples/tinygo/build.sh
Executable file
6
examples/tinygo/build.sh
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
tinygo build -o cart.wasm -target target.json ./main.go
|
||||||
|
uw8 filter-exports cart.wasm cart.wasm && \
|
||||||
|
#wasm-opt -Oz --fast-math --strip-producers -o cart.wasm cart.wasm && \
|
||||||
|
uw8 pack -l 9 cart.wasm cart.uw8
|
||||||
38
examples/tinygo/main.go
Normal file
38
examples/tinygo/main.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:wasm-module env
|
||||||
|
//export atan2
|
||||||
|
func atan2(x, y float32) float32
|
||||||
|
|
||||||
|
//go:wasm-module env
|
||||||
|
//export time
|
||||||
|
func time() float32
|
||||||
|
|
||||||
|
func sqrt(v float32) float32 {
|
||||||
|
return float32(math.Sqrt(float64(v)))
|
||||||
|
}
|
||||||
|
|
||||||
|
var FRAMEBUFFER = (*[320 * 240]byte)(unsafe.Pointer(uintptr(120)))
|
||||||
|
|
||||||
|
//export upd
|
||||||
|
func upd() {
|
||||||
|
var i int
|
||||||
|
for i < 320*240 {
|
||||||
|
t := time() * 63.0
|
||||||
|
x := float32(i%320 - 160)
|
||||||
|
y := float32(i/320 - 120)
|
||||||
|
d := float32(40000.0) / sqrt(x*x+y*y)
|
||||||
|
u := atan2(x, y) * 512.0 / 3.141
|
||||||
|
c := uint8((int(d+t*2.0) ^ int(u+t)) >> 4)
|
||||||
|
FRAMEBUFFER[i] = c
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
}
|
||||||
23
examples/tinygo/target.json
Normal file
23
examples/tinygo/target.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"llvm-target": "wasm32--wasi",
|
||||||
|
"build-tags": [ "tinygo.wasm" ],
|
||||||
|
"goos": "js",
|
||||||
|
"goarch": "wasm",
|
||||||
|
"linker": "wasm-ld",
|
||||||
|
"libc": "wasi-libc",
|
||||||
|
"cflags": [
|
||||||
|
"--target=wasm32--wasi",
|
||||||
|
"--sysroot={root}/lib/wasi-libc/sysroot",
|
||||||
|
"-Oz"
|
||||||
|
],
|
||||||
|
"ldflags": [
|
||||||
|
"--no-entry",
|
||||||
|
"--export-all",
|
||||||
|
"--import-memory",
|
||||||
|
"--initial-memory=262144",
|
||||||
|
"--global-base=81920",
|
||||||
|
"-zstack-size=4096",
|
||||||
|
"--strip-all"
|
||||||
|
],
|
||||||
|
"wasm-abi": "js"
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ loaded.
|
|||||||
00000-00040: user memory
|
00000-00040: user memory
|
||||||
00040-00044: time since module start in ms
|
00040-00044: time since module start in ms
|
||||||
00044-0004c: gamepad state
|
00044-0004c: gamepad state
|
||||||
0004c-00050: reserved
|
0004c-00050: number of frames since module start
|
||||||
00050-00070: sound data (synced to sound thread)
|
00050-00070: sound data (synced to sound thread)
|
||||||
00070-00078: reserved
|
00070-00078: reserved
|
||||||
00078-12c78: frame buffer
|
00078-12c78: frame buffer
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -27,6 +27,7 @@ struct UW8Instance {
|
|||||||
end_frame: TypedFunc<(), ()>,
|
end_frame: TypedFunc<(), ()>,
|
||||||
update: Option<TypedFunc<(), ()>>,
|
update: Option<TypedFunc<(), ()>>,
|
||||||
start_time: Instant,
|
start_time: Instant,
|
||||||
|
frame_counter: u32,
|
||||||
watchdog: Arc<Mutex<UW8WatchDog>>,
|
watchdog: Arc<Mutex<UW8WatchDog>>,
|
||||||
sound_tx: Option<mpsc::SyncSender<RegisterUpdate>>,
|
sound_tx: Option<mpsc::SyncSender<RegisterUpdate>>,
|
||||||
}
|
}
|
||||||
@@ -159,6 +160,7 @@ impl super::Runtime for MicroW8 {
|
|||||||
end_frame,
|
end_frame,
|
||||||
update,
|
update,
|
||||||
start_time: Instant::now(),
|
start_time: Instant::now(),
|
||||||
|
frame_counter: 0,
|
||||||
watchdog,
|
watchdog,
|
||||||
sound_tx,
|
sound_tx,
|
||||||
});
|
});
|
||||||
@@ -191,8 +193,11 @@ impl super::Runtime for MicroW8 {
|
|||||||
let mem = instance.memory.data_mut(&mut instance.store);
|
let mem = instance.memory.data_mut(&mut instance.store);
|
||||||
mem[64..68].copy_from_slice(&time.to_le_bytes());
|
mem[64..68].copy_from_slice(&time.to_le_bytes());
|
||||||
mem[68..72].copy_from_slice(&input.gamepads);
|
mem[68..72].copy_from_slice(&input.gamepads);
|
||||||
|
mem[72..76].copy_from_slice(&instance.frame_counter.to_le_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instance.frame_counter = instance.frame_counter.wrapping_add(1);
|
||||||
|
|
||||||
instance.store.set_epoch_deadline(self.timeout as u64);
|
instance.store.set_epoch_deadline(self.timeout as u64);
|
||||||
if let Some(ref update) = instance.update {
|
if let Some(ref update) = instance.update {
|
||||||
if let Err(err) = update.call(&mut instance.store, ()) {
|
if let Err(err) = update.call(&mut instance.store, ()) {
|
||||||
@@ -328,9 +333,8 @@ fn init_sound(
|
|||||||
let mut configs: Vec<_> = device
|
let mut configs: Vec<_> = device
|
||||||
.supported_output_configs()?
|
.supported_output_configs()?
|
||||||
.filter(|config| {
|
.filter(|config| {
|
||||||
config.channels() <= 2
|
config.sample_format() == cpal::SampleFormat::F32
|
||||||
&& (config.sample_format() == cpal::SampleFormat::F32
|
|| config.sample_format() == cpal::SampleFormat::I16
|
||||||
|| config.sample_format() == cpal::SampleFormat::I16)
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -532,6 +536,25 @@ fn init_sound(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn stereo_to_surround<F>(mut buffer: &mut [f32], num_channels: usize, callback: &mut F)
|
||||||
|
where
|
||||||
|
F: FnMut(&mut [f32]),
|
||||||
|
{
|
||||||
|
let mut in_buffer = [0f32; 256];
|
||||||
|
buffer.fill(0.);
|
||||||
|
|
||||||
|
while !buffer.is_empty() {
|
||||||
|
let step_size = (buffer.len() / num_channels).min(in_buffer.len() / 2);
|
||||||
|
let step_buffer = &mut in_buffer[..step_size * 2];
|
||||||
|
callback(step_buffer);
|
||||||
|
for index in 0..step_size {
|
||||||
|
buffer[index * num_channels + 0] = step_buffer[index * 2 + 0];
|
||||||
|
buffer[index * num_channels + 1] = step_buffer[index * 2 + 1];
|
||||||
|
}
|
||||||
|
buffer = &mut buffer[step_size * num_channels..];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let stream = if sample_format == cpal::SampleFormat::F32 {
|
let stream = if sample_format == cpal::SampleFormat::F32 {
|
||||||
if num_channels == 2 {
|
if num_channels == 2 {
|
||||||
device.build_output_stream(
|
device.build_output_stream(
|
||||||
@@ -542,7 +565,7 @@ fn init_sound(
|
|||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
)?
|
)?
|
||||||
} else {
|
} else if num_channels == 1 {
|
||||||
device.build_output_stream(
|
device.build_output_stream(
|
||||||
&config,
|
&config,
|
||||||
move |buffer: &mut [f32], _| stereo_to_mono(buffer, &mut callback),
|
move |buffer: &mut [f32], _| stereo_to_mono(buffer, &mut callback),
|
||||||
@@ -551,6 +574,17 @@ fn init_sound(
|
|||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
)?
|
)?
|
||||||
|
} else {
|
||||||
|
device.build_output_stream(
|
||||||
|
&config,
|
||||||
|
move |buffer: &mut [f32], _| {
|
||||||
|
stereo_to_surround(buffer, num_channels as usize, &mut callback)
|
||||||
|
},
|
||||||
|
move |err| {
|
||||||
|
dbg!(err);
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)?
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if num_channels == 2 {
|
if num_channels == 2 {
|
||||||
@@ -562,7 +596,7 @@ fn init_sound(
|
|||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
)?
|
)?
|
||||||
} else {
|
} else if num_channels == 1 {
|
||||||
device.build_output_stream(
|
device.build_output_stream(
|
||||||
&config,
|
&config,
|
||||||
move |buffer: &mut [i16], _| {
|
move |buffer: &mut [i16], _| {
|
||||||
@@ -573,6 +607,19 @@ fn init_sound(
|
|||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
)?
|
)?
|
||||||
|
} else {
|
||||||
|
device.build_output_stream(
|
||||||
|
&config,
|
||||||
|
move |buffer: &mut [i16], _| {
|
||||||
|
f32_to_i16(buffer, &mut |b| {
|
||||||
|
stereo_to_surround(b, num_channels as usize, &mut callback)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
move |err| {
|
||||||
|
dbg!(err);
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="uw8">
|
<div id="uw8">
|
||||||
<a href="https://exoticorn.github.io/microw8">MicroW8</a> 0.3.0
|
<a href="https://exoticorn.github.io/microw8">MicroW8</a> 0.3.1
|
||||||
</div>
|
</div>
|
||||||
<div id="centered">
|
<div id="centered">
|
||||||
<canvas class="screen" id="screen" width="320" height="240">
|
<canvas class="screen" id="screen" width="320" height="240">
|
||||||
|
|||||||
@@ -240,6 +240,7 @@ export default function MicroW8(screen, config = {}) {
|
|||||||
await audioReadyPromise;
|
await audioReadyPromise;
|
||||||
|
|
||||||
let startTime = Date.now();
|
let startTime = Date.now();
|
||||||
|
let frameCounter = 0;
|
||||||
|
|
||||||
const timePerFrame = 1000 / 60;
|
const timePerFrame = 1000 / 60;
|
||||||
|
|
||||||
@@ -306,6 +307,7 @@ export default function MicroW8(screen, config = {}) {
|
|||||||
let time = Date.now() - startTime;
|
let time = Date.now() - startTime;
|
||||||
u32Mem[16] = time;
|
u32Mem[16] = time;
|
||||||
u32Mem[17] = pad | gamepad;
|
u32Mem[17] = pad | gamepad;
|
||||||
|
u32Mem[18] = frameCounter++;
|
||||||
if(instance.exports.upd) {
|
if(instance.exports.upd) {
|
||||||
instance.exports.upd();
|
instance.exports.upd();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user