mirror of
https://github.com/exoticorn/microw8.git
synced 2026-01-20 19:26:43 +01:00
Compare commits
3 Commits
v0.2.1-sou
...
testing
| Author | SHA1 | Date | |
|---|---|---|---|
| e30dfb5e81 | |||
| 109a1755b9 | |||
| d1a3bb9db5 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -2,7 +2,7 @@ name: Rust
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ master, testing ]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
|
|||||||
1843
Cargo.lock
generated
1843
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -27,5 +27,5 @@ tokio = { version = "1.17.0", features = ["sync", "rt"], optional = true }
|
|||||||
tokio-stream = { version = "0.1.8", features = ["sync"], optional = true }
|
tokio-stream = { version = "0.1.8", features = ["sync"], optional = true }
|
||||||
webbrowser = { version = "0.6.0", optional = true }
|
webbrowser = { version = "0.6.0", optional = true }
|
||||||
ansi_term = "0.12.1"
|
ansi_term = "0.12.1"
|
||||||
cpal = { version = "0.14.1", optional = true }
|
cpal = { version = "0.13.5", optional = true }
|
||||||
rubato = { version = "0.11.0", optional = true }
|
rubato = { version = "0.11.0", optional = true }
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import "env.rectangle_outline" fn rectangle_outline(f32, f32, f32, f32, i32);
|
|||||||
import "env.circle_outline" fn circle_outline(f32, f32, f32, i32);
|
import "env.circle_outline" fn circle_outline(f32, f32, f32, i32);
|
||||||
import "env.exp" fn exp(f32) -> f32;
|
import "env.exp" fn exp(f32) -> f32;
|
||||||
import "env.playNote" fn playNote(i32, i32);
|
import "env.playNote" fn playNote(i32, i32);
|
||||||
import "env.sndGes" fn sndGes(i32) -> f32;
|
|
||||||
|
|
||||||
const TIME_MS = 0x40;
|
const TIME_MS = 0x40;
|
||||||
const GAMEPAD = 0x44;
|
const GAMEPAD = 0x44;
|
||||||
|
|||||||
@@ -34,7 +34,6 @@
|
|||||||
(import "env" "circle_outline" (func $circle_outline (param f32) (param f32) (param f32) (param i32)))
|
(import "env" "circle_outline" (func $circle_outline (param f32) (param f32) (param f32) (param i32)))
|
||||||
(import "env" "exp" (func $exp (param f32) (result f32)))
|
(import "env" "exp" (func $exp (param f32) (result f32)))
|
||||||
(import "env" "playNote" (func $playNote (param i32) (param i32)))
|
(import "env" "playNote" (func $playNote (param i32) (param i32)))
|
||||||
(import "env" "sndGes" (func $sndGes (param i32) (result f32)))
|
|
||||||
|
|
||||||
;; to use defines, include this file with a preprocessor
|
;; to use defines, include this file with a preprocessor
|
||||||
;; like gpp (https://logological.org/gpp).
|
;; like gpp (https://logological.org/gpp).
|
||||||
|
|||||||
2
platform/Cargo.lock
generated
2
platform/Cargo.lock
generated
@@ -391,7 +391,7 @@ checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "upkr"
|
name = "upkr"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/exoticorn/upkr.git?rev=d93aec186c9fb91d962c488682a2db125c61306c#d93aec186c9fb91d962c488682a2db125c61306c"
|
source = "git+https://github.com/exoticorn/upkr.git?rev=2e7983fc#2e7983fc650788d98da2eecef2d16f63e849e4a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cdivsufsort",
|
"cdivsufsort",
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -10,7 +10,7 @@ const GesState.Size = GesState.Filter + 8*4;
|
|||||||
const GesStateOffset = 32;
|
const GesStateOffset = 32;
|
||||||
const GesBufferOffset = 32 + GesState.Size;
|
const GesBufferOffset = 32 + GesState.Size;
|
||||||
|
|
||||||
export fn sndGes(t: i32) -> f32 {
|
export fn gesSnd(t: i32) -> f32 {
|
||||||
let baseAddr = 0!0x12c78;
|
let baseAddr = 0!0x12c78;
|
||||||
if !(t & 127) {
|
if !(t & 127) {
|
||||||
let i: i32;
|
let i: i32;
|
||||||
@@ -62,6 +62,7 @@ export fn sndGes(t: i32) -> f32 {
|
|||||||
let phase = channelState!GesChannelState.Phase;
|
let phase = channelState!GesChannelState.Phase;
|
||||||
|
|
||||||
let inline pulseWidth = channelReg?1;
|
let inline pulseWidth = channelReg?1;
|
||||||
|
let phaseShift = (pulseWidth - 128) * 255;
|
||||||
let invPhaseInc = 1 as f32 / phaseInc as f32;
|
let invPhaseInc = 1 as f32 / phaseInc as f32;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
@@ -130,7 +131,7 @@ export fn sndGes(t: i32) -> f32 {
|
|||||||
let phaseInc = (freq * (65536.0 / 44100.0)) as i32;
|
let phaseInc = (freq * (65536.0 / 44100.0)) as i32;
|
||||||
|
|
||||||
let phase = channelState!GesChannelState.Phase;
|
let phase = channelState!GesChannelState.Phase;
|
||||||
if modSrc < ch {
|
if modSrc > ch {
|
||||||
phase = phase - (phaseInc << 6);
|
phase = phase - (phaseInc << 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,19 +29,6 @@ Examplers for older versions:
|
|||||||
|
|
||||||
## Versions
|
## Versions
|
||||||
|
|
||||||
### v0.2.1
|
|
||||||
|
|
||||||
* [Web runtime](v0.2.1)
|
|
||||||
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.1/microw8-0.2.1-linux.tgz)
|
|
||||||
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.1/microw8-0.2.1-macos.tgz)
|
|
||||||
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.1/microw8-0.2.1-windows.zip)
|
|
||||||
|
|
||||||
Changes:
|
|
||||||
|
|
||||||
* new gpu accelerated renderer with (optional) crt filter
|
|
||||||
* optimized `hline` function, a big speed-up when drawing large filled circles or rectangles
|
|
||||||
* print fractional size of packed `uw8` cart
|
|
||||||
|
|
||||||
### v0.2.0
|
### v0.2.0
|
||||||
|
|
||||||
* [Web runtime](v0.2.0)
|
* [Web runtime](v0.2.0)
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
|||||||
<section>
|
<section>
|
||||||
<h1 class="text-center heading-text">A WebAssembly based fantasy console</h1>
|
<h1 class="text-center heading-text">A WebAssembly based fantasy console</h1>
|
||||||
</section>
|
</section>
|
||||||
<a href="v0.2.1">
|
<a href="v0.2.0">
|
||||||
<img class="demonstration-gif" style="width:640px;height:480px;image-rendering:pixelated" src="img/technotunnel.png"></img>
|
<img class="demonstration-gif" style="width:640px;height:480px;image-rendering:pixelated" src="img/technotunnel.png"></img>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -81,12 +81,11 @@ fn run(mut args: Arguments) -> Result<()> {
|
|||||||
#[cfg(not(feature = "native"))]
|
#[cfg(not(feature = "native"))]
|
||||||
let run_browser = args.contains(["-b", "--browser"]) || true;
|
let run_browser = args.contains(["-b", "--browser"]) || true;
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
let disable_audio = args.contains(["-m", "--no-audio"]);
|
let disable_audio = args.contains(["-m", "--no-audio"]);
|
||||||
|
|
||||||
#[cfg(feature = "native")]
|
#[cfg(feature = "native")]
|
||||||
let window_config = {
|
let window_config = {
|
||||||
let mut config = uw8_window::WindowConfig::default();
|
let mut config = WindowConfig::default();
|
||||||
if !run_browser {
|
if !run_browser {
|
||||||
config.parse_arguments(&mut args);
|
config.parse_arguments(&mut args);
|
||||||
}
|
}
|
||||||
@@ -99,6 +98,8 @@ fn run(mut args: Arguments) -> Result<()> {
|
|||||||
|
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
|
use uw8_window::WindowConfig;
|
||||||
|
|
||||||
let mut runtime: Box<dyn Runtime> = if !run_browser {
|
let mut runtime: Box<dyn Runtime> = if !run_browser {
|
||||||
#[cfg(not(feature = "native"))]
|
#[cfg(not(feature = "native"))]
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -314,7 +314,7 @@ fn init_sound(
|
|||||||
|
|
||||||
let snd = instance
|
let snd = instance
|
||||||
.get_typed_func::<(i32,), f32, _>(&mut store, "snd")
|
.get_typed_func::<(i32,), f32, _>(&mut store, "snd")
|
||||||
.or_else(|_| platform_instance.get_typed_func::<(i32,), f32, _>(&mut store, "sndGes"))?;
|
.or_else(|_| platform_instance.get_typed_func::<(i32,), f32, _>(&mut store, "gesSnd"))?;
|
||||||
|
|
||||||
let host = cpal::default_host();
|
let host = cpal::default_host();
|
||||||
let device = host
|
let device = host
|
||||||
@@ -342,7 +342,7 @@ fn init_sound(
|
|||||||
.ok_or_else(|| anyhow!("Could not find float output config"))?;
|
.ok_or_else(|| anyhow!("Could not find float output config"))?;
|
||||||
let sample_rate = cpal::SampleRate(44100)
|
let sample_rate = cpal::SampleRate(44100)
|
||||||
.max(config.min_sample_rate())
|
.max(config.min_sample_rate())
|
||||||
.min(config.max_sample_rate());
|
.max(config.max_sample_rate());
|
||||||
let config = config.with_sample_rate(sample_rate);
|
let config = config.with_sample_rate(sample_rate);
|
||||||
let buffer_size = match *config.buffer_size() {
|
let buffer_size = match *config.buffer_size() {
|
||||||
cpal::SupportedBufferSize::Unknown => cpal::BufferSize::Default,
|
cpal::SupportedBufferSize::Unknown => cpal::BufferSize::Default,
|
||||||
@@ -419,14 +419,6 @@ fn init_sound(
|
|||||||
mem[64..68].copy_from_slice(¤t_time.to_le_bytes());
|
mem[64..68].copy_from_slice(¤t_time.to_le_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clamp_sample(s: f32) -> f32 {
|
|
||||||
if s.is_nan() {
|
|
||||||
0.0
|
|
||||||
} else {
|
|
||||||
s.max(-1.0).min(1.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ref mut resampler) = resampler {
|
if let Some(ref mut resampler) = resampler {
|
||||||
while !buffer.is_empty() {
|
while !buffer.is_empty() {
|
||||||
let copy_size = resampler.output_buffers[0]
|
let copy_size = resampler.output_buffers[0]
|
||||||
@@ -437,12 +429,10 @@ fn init_sound(
|
|||||||
resampler.input_buffers[0].clear();
|
resampler.input_buffers[0].clear();
|
||||||
resampler.input_buffers[1].clear();
|
resampler.input_buffers[1].clear();
|
||||||
for _ in 0..resampler.resampler.input_frames_next() {
|
for _ in 0..resampler.resampler.input_frames_next() {
|
||||||
resampler.input_buffers[0].push(clamp_sample(
|
resampler.input_buffers[0]
|
||||||
snd.call(&mut store, (sample_index,)).unwrap_or(0.0),
|
.push(snd.call(&mut store, (sample_index,)).unwrap_or(0.0));
|
||||||
));
|
resampler.input_buffers[1]
|
||||||
resampler.input_buffers[1].push(clamp_sample(
|
.push(snd.call(&mut store, (sample_index + 1,)).unwrap_or(0.0));
|
||||||
snd.call(&mut store, (sample_index + 1,)).unwrap_or(0.0),
|
|
||||||
));
|
|
||||||
sample_index = sample_index.wrapping_add(2);
|
sample_index = sample_index.wrapping_add(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,7 +458,7 @@ fn init_sound(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for v in buffer {
|
for v in buffer {
|
||||||
*v = clamp_sample(snd.call(&mut store, (sample_index,)).unwrap_or(0.0));
|
*v = snd.call(&mut store, (sample_index,)).unwrap_or(0.0);
|
||||||
sample_index = sample_index.wrapping_add(1);
|
sample_index = sample_index.wrapping_add(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,7 +167,6 @@ impl BaseModule {
|
|||||||
add_function(&mut functions, &type_map, "exp", &[F32], Some(F32));
|
add_function(&mut functions, &type_map, "exp", &[F32], Some(F32));
|
||||||
|
|
||||||
add_function(&mut functions, &type_map, "playNote", &[I32, I32], None);
|
add_function(&mut functions, &type_map, "playNote", &[I32, I32], None);
|
||||||
add_function(&mut functions, &type_map, "sndGes", &[I32], Some(F32));
|
|
||||||
|
|
||||||
for i in functions.len()..64 {
|
for i in functions.len()..64 {
|
||||||
add_function(
|
add_function(
|
||||||
|
|||||||
@@ -220,11 +220,6 @@ impl<'a> ParsedModule<'a> {
|
|||||||
validate_table_section(reader)?;
|
validate_table_section(reader)?;
|
||||||
table_section = Some(Section::new(range, ()));
|
table_section = Some(Section::new(range, ()));
|
||||||
}
|
}
|
||||||
Payload::MemorySection(reader) => {
|
|
||||||
if reader.get_count() != 0 {
|
|
||||||
bail!("Found non-empty MemorySection. Memory has to be imported!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Payload::ElementSection(mut reader) => {
|
Payload::ElementSection(mut reader) => {
|
||||||
let mut elements = Vec::with_capacity(reader.get_count() as usize);
|
let mut elements = Vec::with_capacity(reader.get_count() as usize);
|
||||||
for _ in 0..reader.get_count() {
|
for _ in 0..reader.get_count() {
|
||||||
|
|||||||
@@ -15,4 +15,4 @@ pollster = "0.2"
|
|||||||
bytemuck = { version = "1.4", features = [ "derive" ] }
|
bytemuck = { version = "1.4", features = [ "derive" ] }
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
minifb = { version = "0.23.0", default-features = false, features = ["x11"] }
|
minifb = { version = "0.23.0", default-features = false, features = ["x11"] }
|
||||||
winapi = { version = "0.3.9", features = ["std"] }
|
winapi = "0.3.9"
|
||||||
|
|||||||
@@ -4,64 +4,31 @@ use std::time::Instant;
|
|||||||
mod cpu;
|
mod cpu;
|
||||||
mod gpu;
|
mod gpu;
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window(Box<dyn WindowImpl>);
|
||||||
inner: Box<dyn WindowImpl>,
|
|
||||||
fps_counter: Option<FpsCounter>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FpsCounter {
|
|
||||||
start: Instant,
|
|
||||||
num_frames: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(config: WindowConfig) -> Result<Window> {
|
pub fn new(config: WindowConfig) -> Result<Window> {
|
||||||
let fps_counter = if config.fps_counter {
|
|
||||||
Some(FpsCounter {
|
|
||||||
start: Instant::now(),
|
|
||||||
num_frames: 0,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
if config.enable_gpu {
|
if config.enable_gpu {
|
||||||
match gpu::Window::new(config) {
|
match gpu::Window::new(config) {
|
||||||
Ok(window) => {
|
Ok(window) => return Ok(Window(Box::new(window))),
|
||||||
return Ok(Window {
|
|
||||||
inner: Box::new(window),
|
|
||||||
fps_counter,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Err(err) => eprintln!(
|
Err(err) => eprintln!(
|
||||||
"Failed to create gpu window: {}\nFalling back tp cpu window",
|
"Failed to create gpu window: {}\nFalling back tp cpu window",
|
||||||
err
|
err
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cpu::Window::new().map(|window| Window {
|
cpu::Window::new().map(|window| Window(Box::new(window)))
|
||||||
inner: Box::new(window),
|
|
||||||
fps_counter,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn begin_frame(&mut self) -> Input {
|
pub fn begin_frame(&mut self) -> Input {
|
||||||
self.inner.begin_frame()
|
self.0.begin_frame()
|
||||||
}
|
}
|
||||||
pub fn end_frame(&mut self, framebuffer: &[u8], palette: &[u8], next_frame: Instant) {
|
pub fn end_frame(&mut self, framebuffer: &[u8], palette: &[u8], next_frame: Instant) {
|
||||||
self.inner.end_frame(framebuffer, palette, next_frame);
|
self.0.end_frame(framebuffer, palette, next_frame)
|
||||||
if let Some(ref mut fps_counter) = self.fps_counter {
|
|
||||||
fps_counter.num_frames += 1;
|
|
||||||
let elapsed = fps_counter.start.elapsed().as_secs_f32();
|
|
||||||
if elapsed >= 1.0 {
|
|
||||||
println!("fps: {:.1}", fps_counter.num_frames as f32 / elapsed);
|
|
||||||
fps_counter.num_frames = 0;
|
|
||||||
fps_counter.start = Instant::now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_open(&self) -> bool {
|
pub fn is_open(&self) -> bool {
|
||||||
self.inner.is_open()
|
self.0.is_open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +37,6 @@ pub struct WindowConfig {
|
|||||||
enable_gpu: bool,
|
enable_gpu: bool,
|
||||||
filter: u32,
|
filter: u32,
|
||||||
fullscreen: bool,
|
fullscreen: bool,
|
||||||
fps_counter: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WindowConfig {
|
impl Default for WindowConfig {
|
||||||
@@ -79,7 +45,6 @@ impl Default for WindowConfig {
|
|||||||
enable_gpu: true,
|
enable_gpu: true,
|
||||||
filter: 5,
|
filter: 5,
|
||||||
fullscreen: false,
|
fullscreen: false,
|
||||||
fps_counter: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,7 +66,6 @@ impl WindowConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.fullscreen = args.contains("--fullscreen");
|
self.fullscreen = args.contains("--fullscreen");
|
||||||
self.fps_counter = args.contains("--fps");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class APU extends AudioWorkletProcessor {
|
|||||||
|
|
||||||
this.memory = memory;
|
this.memory = memory;
|
||||||
|
|
||||||
this.snd = instance.exports.snd || platform_instance.exports.sndGes;
|
this.snd = instance.exports.snd || platform_instance.exports.gesSnd;
|
||||||
|
|
||||||
this.port.postMessage(2);
|
this.port.postMessage(2);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user