mirror of
https://github.com/exoticorn/microw8.git
synced 2026-01-20 11:16:42 +01:00
Compare commits
8 Commits
zig-game
...
9d437457f7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d437457f7 | ||
| a651107104 | |||
| 22c35e37f4 | |||
| 805c939097 | |||
| 440e150896 | |||
| 77b2e27346 | |||
| 09e4fcbf14 | |||
|
|
937ccf60c9 |
2313
Cargo.lock
generated
2313
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
16
Cargo.toml
16
Cargo.toml
@@ -11,21 +11,21 @@ native = ["wasmtime", "uw8-window", "cpal", "rubato" ]
|
||||
browser = ["warp", "tokio", "tokio-stream", "webbrowser"]
|
||||
|
||||
[dependencies]
|
||||
wasmtime = { version = "5.0.0", optional = true }
|
||||
wasmtime = { version = "12.0.0", optional = true }
|
||||
anyhow = "1"
|
||||
env_logger = "0.10"
|
||||
log = "0.4"
|
||||
uw8-window = { path = "uw8-window", optional = true }
|
||||
notify-debouncer-mini = { version = "0.2.1", default-features = false }
|
||||
notify-debouncer-mini = { version = "0.4.1", default-features = false }
|
||||
pico-args = "0.5"
|
||||
curlywas = { git = "https://github.com/exoticorn/curlywas.git", rev = "0e7ea50" }
|
||||
wat = "1"
|
||||
uw8-tool = { path = "uw8-tool" }
|
||||
same-file = "1"
|
||||
warp = { version = "0.3.3", optional = true }
|
||||
tokio = { version = "1.24.0", features = ["sync", "rt"], optional = true }
|
||||
tokio-stream = { version = "0.1.11", features = ["sync"], optional = true }
|
||||
webbrowser = { version = "0.8.6", optional = true }
|
||||
warp = { version = "0.3.5", optional = true }
|
||||
tokio = { version = "1.32.0", features = ["sync", "rt"], optional = true }
|
||||
tokio-stream = { version = "0.1.14", features = ["sync"], optional = true }
|
||||
webbrowser = { version = "0.8.11", optional = true }
|
||||
ansi_term = "0.12.1"
|
||||
cpal = { version = "0.14.2", optional = true }
|
||||
rubato = { version = "0.12.0", optional = true }
|
||||
cpal = { version = "0.15.2", optional = true }
|
||||
rubato = { version = "0.14.0", optional = true }
|
||||
|
||||
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"
|
||||
}
|
||||
@@ -62,7 +62,6 @@ export fn sndGes(t: i32) -> f32 {
|
||||
let phase = channelState!GesChannelState.Phase;
|
||||
|
||||
let inline pulseWidth = channelReg?1;
|
||||
let phaseShift = (pulseWidth - 128) * 255;
|
||||
let invPhaseInc = 1 as f32 / phaseInc as f32;
|
||||
|
||||
i = 0;
|
||||
@@ -131,7 +130,7 @@ export fn sndGes(t: i32) -> f32 {
|
||||
let phaseInc = (freq * (65536.0 / 44100.0)) as i32;
|
||||
|
||||
let phase = channelState!GesChannelState.Phase;
|
||||
if modSrc > ch {
|
||||
if modSrc < ch {
|
||||
phase = phase - (phaseInc << 6);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,16 +16,14 @@ pub struct FileWatcher {
|
||||
impl FileWatcher {
|
||||
pub fn new() -> Result<FileWatcher> {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let debouncer = new_debouncer(Duration::from_millis(100), None, move |res| match res {
|
||||
let debouncer = new_debouncer(Duration::from_millis(100), move |res| match res {
|
||||
Ok(events) => {
|
||||
for event in events {
|
||||
let _ = tx.send(event);
|
||||
}
|
||||
}
|
||||
Err(errs) => {
|
||||
for err in errs {
|
||||
eprintln!("Error watching for file changes: {err}");
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("Error watching for file changes: {err}");
|
||||
}
|
||||
})?;
|
||||
Ok(FileWatcher {
|
||||
|
||||
@@ -7,7 +7,7 @@ use cpal::traits::*;
|
||||
use rubato::Resampler;
|
||||
use uw8_window::{Window, WindowConfig};
|
||||
use wasmtime::{
|
||||
Engine, GlobalType, Memory, MemoryType, Module, Mutability, Store, TypedFunc, ValType,
|
||||
Engine, Func, GlobalType, Memory, MemoryType, Module, Mutability, Store, TypedFunc, ValType,
|
||||
};
|
||||
|
||||
pub struct MicroW8 {
|
||||
@@ -90,7 +90,7 @@ impl super::Runtime for MicroW8 {
|
||||
let memory = wasmtime::Memory::new(&mut store, MemoryType::new(4, Some(4)))?;
|
||||
|
||||
let mut linker = wasmtime::Linker::new(&self.engine);
|
||||
linker.define("env", "memory", memory)?;
|
||||
linker.define(&store, "env", "memory", memory)?;
|
||||
|
||||
let loader_instance = linker.instantiate(&mut store, &self.loader_module)?;
|
||||
let load_uw8 = loader_instance.get_typed_func::<i32, i32>(&mut store, "load_uw8")?;
|
||||
@@ -255,15 +255,12 @@ fn add_native_functions(
|
||||
}
|
||||
})?;
|
||||
for i in 0..16 {
|
||||
linker.define(
|
||||
"env",
|
||||
&format!("g_reserved{}", i),
|
||||
wasmtime::Global::new(
|
||||
&mut *store,
|
||||
GlobalType::new(ValType::I32, Mutability::Const),
|
||||
0.into(),
|
||||
)?,
|
||||
let global = wasmtime::Global::new(
|
||||
&mut *store,
|
||||
GlobalType::new(ValType::I32, Mutability::Const),
|
||||
0.into(),
|
||||
)?;
|
||||
linker.define(&store, "env", &format!("g_reserved{}", i), global)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -276,14 +273,18 @@ fn instantiate_platform(
|
||||
) -> Result<wasmtime::Instance> {
|
||||
let platform_instance = linker.instantiate(&mut *store, &platform_module)?;
|
||||
|
||||
for export in platform_instance.exports(&mut *store) {
|
||||
linker.define(
|
||||
"env",
|
||||
export.name(),
|
||||
export
|
||||
.into_func()
|
||||
.expect("platform surely only exports functions"),
|
||||
)?;
|
||||
let exports: Vec<(String, Func)> = platform_instance
|
||||
.exports(&mut *store)
|
||||
.map(|e| {
|
||||
(
|
||||
e.name().to_owned(),
|
||||
e.into_func()
|
||||
.expect("platform surely only exports functions"),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
for (name, func) in exports {
|
||||
linker.define(&store, "env", &name, func)?;
|
||||
}
|
||||
|
||||
Ok(platform_instance)
|
||||
@@ -310,7 +311,7 @@ fn init_sound(
|
||||
let memory = wasmtime::Memory::new(&mut store, MemoryType::new(4, Some(4)))?;
|
||||
|
||||
let mut linker = wasmtime::Linker::new(engine);
|
||||
linker.define("env", "memory", memory)?;
|
||||
linker.define(&store, "env", "memory", memory)?;
|
||||
add_native_functions(&mut linker, &mut store)?;
|
||||
|
||||
let platform_instance = instantiate_platform(&mut linker, &mut store, platform_module)?;
|
||||
@@ -327,23 +328,26 @@ fn init_sound(
|
||||
let mut configs: Vec<_> = device
|
||||
.supported_output_configs()?
|
||||
.filter(|config| {
|
||||
config.channels() == 2 && config.sample_format() == cpal::SampleFormat::F32
|
||||
config.channels() == 2
|
||||
&& (config.sample_format() == cpal::SampleFormat::F32
|
||||
|| config.sample_format() == cpal::SampleFormat::I16)
|
||||
})
|
||||
.collect();
|
||||
configs.sort_by_key(|config| {
|
||||
let rate = 44100
|
||||
.max(config.min_sample_rate().0)
|
||||
.min(config.max_sample_rate().0);
|
||||
if rate >= 44100 {
|
||||
let prio = if rate >= 44100 {
|
||||
rate - 44100
|
||||
} else {
|
||||
(44100 - rate) * 1000
|
||||
}
|
||||
};
|
||||
prio + (config.sample_format() == cpal::SampleFormat::I16) as u32
|
||||
});
|
||||
let config = configs
|
||||
.into_iter()
|
||||
.next()
|
||||
.ok_or_else(|| anyhow!("Could not find float output config"))?;
|
||||
.ok_or_else(|| anyhow!("Could not find float or 16bit signed output config"))?;
|
||||
let sample_rate = cpal::SampleRate(44100)
|
||||
.max(config.min_sample_rate())
|
||||
.min(config.max_sample_rate());
|
||||
@@ -354,6 +358,7 @@ fn init_sound(
|
||||
cpal::BufferSize::Fixed(256.max(min).min(max))
|
||||
}
|
||||
};
|
||||
let sample_format = config.sample_format();
|
||||
let config = cpal::StreamConfig {
|
||||
buffer_size,
|
||||
..config.config()
|
||||
@@ -373,8 +378,8 @@ fn init_sound(
|
||||
None
|
||||
} else {
|
||||
let rs = rubato::FftFixedIn::new(44100, sample_rate, 128, 1, 2)?;
|
||||
let input_buffers = rs.input_buffer_allocate();
|
||||
let output_buffers = rs.output_buffer_allocate();
|
||||
let input_buffers = rs.input_buffer_allocate(true);
|
||||
let output_buffers = rs.output_buffer_allocate(true);
|
||||
Some(Resampler {
|
||||
resampler: rs,
|
||||
input_buffers,
|
||||
@@ -386,96 +391,130 @@ fn init_sound(
|
||||
let mut sample_index = 0;
|
||||
let mut pending_updates: Vec<RegisterUpdate> = Vec::with_capacity(30);
|
||||
let mut current_time = 0;
|
||||
let stream = device.build_output_stream(
|
||||
&config,
|
||||
move |mut outer_buffer: &mut [f32], _| {
|
||||
let mut first_update = true;
|
||||
while let Ok(update) = rx.try_recv() {
|
||||
if first_update {
|
||||
current_time += update.time.wrapping_sub(current_time) / 8;
|
||||
first_update = false;
|
||||
}
|
||||
pending_updates.push(update);
|
||||
|
||||
let mut callback = move |mut outer_buffer: &mut [f32], _: &_| {
|
||||
let mut first_update = true;
|
||||
while let Ok(update) = rx.try_recv() {
|
||||
if first_update {
|
||||
current_time += update.time.wrapping_sub(current_time) / 8;
|
||||
first_update = false;
|
||||
}
|
||||
pending_updates.push(update);
|
||||
}
|
||||
|
||||
while !outer_buffer.is_empty() {
|
||||
store.set_epoch_deadline(30);
|
||||
while pending_updates
|
||||
.first()
|
||||
.into_iter()
|
||||
.any(|u| u.time.wrapping_sub(current_time) <= 0)
|
||||
{
|
||||
let update = pending_updates.remove(0);
|
||||
memory.write(&mut store, 80, &update.data).unwrap();
|
||||
}
|
||||
|
||||
while !outer_buffer.is_empty() {
|
||||
store.set_epoch_deadline(30);
|
||||
while pending_updates
|
||||
.first()
|
||||
.into_iter()
|
||||
.any(|u| u.time.wrapping_sub(current_time) <= 0)
|
||||
{
|
||||
let update = pending_updates.remove(0);
|
||||
memory.write(&mut store, 80, &update.data).unwrap();
|
||||
}
|
||||
let duration = if let Some(update) = pending_updates.first() {
|
||||
((update.time.wrapping_sub(current_time) as usize) * sample_rate + 999) / 1000
|
||||
} else {
|
||||
outer_buffer.len()
|
||||
};
|
||||
let step_size = (duration.max(64) * 2).min(outer_buffer.len());
|
||||
|
||||
let duration = if let Some(update) = pending_updates.first() {
|
||||
((update.time.wrapping_sub(current_time) as usize) * sample_rate + 999) / 1000
|
||||
let mut buffer = &mut outer_buffer[..step_size];
|
||||
|
||||
{
|
||||
let mem = memory.data_mut(&mut store);
|
||||
mem[64..68].copy_from_slice(¤t_time.to_le_bytes());
|
||||
}
|
||||
|
||||
fn clamp_sample(s: f32) -> f32 {
|
||||
if s.is_nan() {
|
||||
0.0
|
||||
} else {
|
||||
outer_buffer.len()
|
||||
};
|
||||
let step_size = (duration.max(64) * 2).min(outer_buffer.len());
|
||||
|
||||
let mut buffer = &mut outer_buffer[..step_size];
|
||||
|
||||
{
|
||||
let mem = memory.data_mut(&mut store);
|
||||
mem[64..68].copy_from_slice(¤t_time.to_le_bytes());
|
||||
s.max(-1.0).min(1.0)
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref mut resampler) = resampler {
|
||||
while !buffer.is_empty() {
|
||||
let copy_size = resampler.output_buffers[0]
|
||||
.len()
|
||||
.saturating_sub(resampler.output_index)
|
||||
.min(buffer.len() / 2);
|
||||
if copy_size == 0 {
|
||||
resampler.input_buffers[0].clear();
|
||||
resampler.input_buffers[1].clear();
|
||||
for _ in 0..resampler.resampler.input_frames_next() {
|
||||
resampler.input_buffers[0]
|
||||
.push(snd.call(&mut store, (sample_index,)).unwrap_or(0.0));
|
||||
resampler.input_buffers[1]
|
||||
.push(snd.call(&mut store, (sample_index + 1,)).unwrap_or(0.0));
|
||||
sample_index = sample_index.wrapping_add(2);
|
||||
}
|
||||
|
||||
resampler
|
||||
.resampler
|
||||
.process_into_buffer(
|
||||
&resampler.input_buffers,
|
||||
&mut resampler.output_buffers,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
resampler.output_index = 0;
|
||||
} else {
|
||||
for i in 0..copy_size {
|
||||
buffer[i * 2] =
|
||||
resampler.output_buffers[0][resampler.output_index + i];
|
||||
buffer[i * 2 + 1] =
|
||||
resampler.output_buffers[1][resampler.output_index + i];
|
||||
}
|
||||
resampler.output_index += copy_size;
|
||||
buffer = &mut buffer[copy_size * 2..];
|
||||
if let Some(ref mut resampler) = resampler {
|
||||
while !buffer.is_empty() {
|
||||
let copy_size = resampler.output_buffers[0]
|
||||
.len()
|
||||
.saturating_sub(resampler.output_index)
|
||||
.min(buffer.len() / 2);
|
||||
if copy_size == 0 {
|
||||
resampler.input_buffers[0].clear();
|
||||
resampler.input_buffers[1].clear();
|
||||
for _ in 0..resampler.resampler.input_frames_next() {
|
||||
resampler.input_buffers[0].push(clamp_sample(
|
||||
snd.call(&mut store, (sample_index,)).unwrap_or(0.0),
|
||||
));
|
||||
resampler.input_buffers[1].push(clamp_sample(
|
||||
snd.call(&mut store, (sample_index + 1,)).unwrap_or(0.0),
|
||||
));
|
||||
sample_index = sample_index.wrapping_add(2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for v in buffer {
|
||||
*v = snd.call(&mut store, (sample_index,)).unwrap_or(0.0);
|
||||
sample_index = sample_index.wrapping_add(1);
|
||||
|
||||
resampler
|
||||
.resampler
|
||||
.process_into_buffer(
|
||||
&resampler.input_buffers,
|
||||
&mut resampler.output_buffers,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
resampler.output_index = 0;
|
||||
} else {
|
||||
for i in 0..copy_size {
|
||||
buffer[i * 2] = resampler.output_buffers[0][resampler.output_index + i];
|
||||
buffer[i * 2 + 1] =
|
||||
resampler.output_buffers[1][resampler.output_index + i];
|
||||
}
|
||||
resampler.output_index += copy_size;
|
||||
buffer = &mut buffer[copy_size * 2..];
|
||||
}
|
||||
}
|
||||
|
||||
outer_buffer = &mut outer_buffer[step_size..];
|
||||
current_time =
|
||||
current_time.wrapping_add((step_size * 500 / sample_rate).max(1) as i32);
|
||||
} else {
|
||||
for v in buffer {
|
||||
*v = clamp_sample(snd.call(&mut store, (sample_index,)).unwrap_or(0.0));
|
||||
sample_index = sample_index.wrapping_add(1);
|
||||
}
|
||||
}
|
||||
},
|
||||
move |err| {
|
||||
dbg!(err);
|
||||
},
|
||||
)?;
|
||||
|
||||
outer_buffer = &mut outer_buffer[step_size..];
|
||||
current_time = current_time.wrapping_add((step_size * 500 / sample_rate).max(1) as i32);
|
||||
}
|
||||
};
|
||||
let stream = if sample_format == cpal::SampleFormat::F32 {
|
||||
device.build_output_stream(
|
||||
&config,
|
||||
callback,
|
||||
move |err| {
|
||||
dbg!(err);
|
||||
},
|
||||
None,
|
||||
)?
|
||||
} else {
|
||||
device.build_output_stream(
|
||||
&config,
|
||||
move |mut buffer: &mut [i16], info| {
|
||||
let mut float_buffer = [0f32; 256];
|
||||
|
||||
while !buffer.is_empty() {
|
||||
let step_size = buffer.len().min(float_buffer.len());
|
||||
let step_buffer = &mut float_buffer[..step_size];
|
||||
callback(step_buffer, info);
|
||||
for (dest, src) in buffer.iter_mut().take(step_size).zip(step_buffer.iter()) {
|
||||
*dest = (src.max(-1.0).min(1.0) * 32767.0) as i16;
|
||||
}
|
||||
buffer = &mut buffer[step_size..];
|
||||
}
|
||||
},
|
||||
move |err| {
|
||||
dbg!(err);
|
||||
},
|
||||
None,
|
||||
)?
|
||||
};
|
||||
|
||||
Ok(Uw8Sound { stream, tx })
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
use std::path::Path;
|
||||
use anyhow::Result;
|
||||
use std::path::Path;
|
||||
|
||||
pub fn filter_exports(in_path: &Path, out_path: &Path) -> Result<()> {
|
||||
let mut module = walrus::Module::from_file(in_path)?;
|
||||
|
||||
let exports_to_delete: Vec<_> = module.exports.iter().filter_map(|export| match export.name.as_str() {
|
||||
"upd" => None,
|
||||
_ => Some(export.id())
|
||||
}).collect();
|
||||
let exports_to_delete: Vec<_> = module
|
||||
.exports
|
||||
.iter()
|
||||
.filter_map(|export| match export.name.as_str() {
|
||||
"start" | "upd" | "snd" => None,
|
||||
_ => Some(export.id()),
|
||||
})
|
||||
.collect();
|
||||
|
||||
for id in exports_to_delete {
|
||||
module.exports.delete(id);
|
||||
@@ -18,4 +22,4 @@ pub fn filter_exports(in_path: &Path, out_path: &Path) -> Result<()> {
|
||||
module.emit_wasm_file(out_path)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
810
uw8-window/Cargo.lock
generated
810
uw8-window/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -6,13 +6,13 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
winit = "0.27.5"
|
||||
winit = "0.28.6"
|
||||
env_logger = "0.10"
|
||||
log = "0.4"
|
||||
pico-args = "0.5"
|
||||
wgpu = "0.15"
|
||||
pollster = "0.2.5"
|
||||
wgpu = "0.17"
|
||||
pollster = "0.3.0"
|
||||
bytemuck = { version = "1.13", features = [ "derive" ] }
|
||||
anyhow = "1"
|
||||
minifb = { version = "0.23.0", default-features = false, features = ["x11"] }
|
||||
minifb = { version = "0.25.0", default-features = false, features = ["x11"] }
|
||||
winapi = { version = "0.3.9", features = [ "timeapi" ] }
|
||||
|
||||
@@ -30,8 +30,8 @@ fn row_factor(offset: f32) -> f32 {
|
||||
}
|
||||
|
||||
fn col_factor(offset: f32) -> f32 {
|
||||
let offset = max(0.0, abs(offset) - 0.4);
|
||||
return 1.0 / (1.0 + offset * offset * 16.0);
|
||||
let o = max(0.0, abs(offset) - 0.4);
|
||||
return 1.0 / (1.0 + o * o * 16.0);
|
||||
}
|
||||
|
||||
fn sample_screen(tex_coords: vec2<f32>) -> vec4<f32> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{Input, WindowConfig, WindowImpl};
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::{num::NonZeroU32, time::Instant};
|
||||
use std::time::Instant;
|
||||
|
||||
use winit::{
|
||||
dpi::PhysicalSize,
|
||||
@@ -41,7 +41,10 @@ impl Window {
|
||||
async fn create(window_config: WindowConfig) -> Result<Window> {
|
||||
let event_loop = EventLoop::new();
|
||||
let window = WindowBuilder::new()
|
||||
.with_inner_size(PhysicalSize::new(640u32, 480))
|
||||
.with_inner_size(PhysicalSize::new(
|
||||
(320. * window_config.scale).round() as u32,
|
||||
(240. * window_config.scale).round() as u32,
|
||||
))
|
||||
.with_min_inner_size(PhysicalSize::new(320u32, 240))
|
||||
.with_title("MicroW8")
|
||||
.with_fullscreen(if window_config.fullscreen {
|
||||
@@ -72,7 +75,13 @@ impl Window {
|
||||
|
||||
let surface_config = wgpu::SurfaceConfiguration {
|
||||
present_mode: wgpu::PresentMode::AutoNoVsync,
|
||||
..surface.get_default_config(&adapter, window.inner_size().width, window.inner_size().height).expect("Surface incompatible with adapter")
|
||||
..surface
|
||||
.get_default_config(
|
||||
&adapter,
|
||||
window.inner_size().width,
|
||||
window.inner_size().height,
|
||||
)
|
||||
.expect("Surface incompatible with adapter")
|
||||
};
|
||||
|
||||
let filter: Box<dyn Filter> = create_filter(
|
||||
@@ -354,7 +363,7 @@ impl PaletteScreenMode {
|
||||
format: wgpu::TextureFormat::R8Uint,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||
label: None,
|
||||
view_formats: &[]
|
||||
view_formats: &[],
|
||||
});
|
||||
|
||||
let palette_texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
@@ -369,7 +378,7 @@ impl PaletteScreenMode {
|
||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||
label: None,
|
||||
view_formats: &[]
|
||||
view_formats: &[],
|
||||
});
|
||||
|
||||
let screen_texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
@@ -384,7 +393,7 @@ impl PaletteScreenMode {
|
||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
label: None,
|
||||
view_formats: &[]
|
||||
view_formats: &[],
|
||||
});
|
||||
|
||||
let framebuffer_texture_view =
|
||||
@@ -491,7 +500,7 @@ impl PaletteScreenMode {
|
||||
&bytemuck::cast_slice(pixels),
|
||||
wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: NonZeroU32::new(320),
|
||||
bytes_per_row: Some(320),
|
||||
rows_per_image: None,
|
||||
},
|
||||
wgpu::Extent3d {
|
||||
@@ -513,7 +522,7 @@ impl PaletteScreenMode {
|
||||
&bytemuck::cast_slice(palette),
|
||||
wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: NonZeroU32::new(256 * 4),
|
||||
bytes_per_row: Some(256 * 4),
|
||||
rows_per_image: None,
|
||||
},
|
||||
wgpu::Extent3d {
|
||||
|
||||
@@ -15,7 +15,7 @@ struct FpsCounter {
|
||||
}
|
||||
|
||||
impl Window {
|
||||
pub fn new(config: WindowConfig) -> Result<Window> {
|
||||
pub fn new(mut config: WindowConfig) -> Result<Window> {
|
||||
let fps_counter = if config.fps_counter {
|
||||
Some(FpsCounter {
|
||||
start: Instant::now(),
|
||||
@@ -24,6 +24,7 @@ impl Window {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
config.scale = config.scale.max(1.).min(20.);
|
||||
if config.enable_gpu {
|
||||
match gpu::Window::new(config) {
|
||||
Ok(window) => {
|
||||
@@ -71,6 +72,7 @@ pub struct WindowConfig {
|
||||
filter: u32,
|
||||
fullscreen: bool,
|
||||
fps_counter: bool,
|
||||
scale: f32,
|
||||
}
|
||||
|
||||
impl Default for WindowConfig {
|
||||
@@ -80,6 +82,7 @@ impl Default for WindowConfig {
|
||||
filter: 5,
|
||||
fullscreen: false,
|
||||
fps_counter: false,
|
||||
scale: 2.,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,6 +105,10 @@ impl WindowConfig {
|
||||
}
|
||||
self.fullscreen = args.contains("--fullscreen");
|
||||
self.fps_counter = args.contains("--fps");
|
||||
self.scale = args
|
||||
.opt_value_from_str("--scale")
|
||||
.unwrap()
|
||||
.unwrap_or(self.scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user