Compare commits

...

4 commits

17 changed files with 602 additions and 958 deletions

View file

@ -1,5 +1,5 @@
[alias] [alias]
xtask = "run --package xtask --" xtask = "run -q --package xtask --"
[profile.dev] [profile.dev]
opt-level = 1 opt-level = 1

1234
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,7 @@ resolver = "2"
[workspace.dependencies] [workspace.dependencies]
log = "0.4.22" log = "0.4.22"
env_logger = "0.11.5" env_logger = "0.11.5"
thiserror = "1.0.63" thiserror = "1.0.65"
raw-window-handle = "0.6.2" raw-window-handle = "0.6.2"
gb-emu-lib = { path = "./lib", features = ["config"] } gb-emu-lib = { path = "./lib", features = ["config"] }
frontend-common = { path = "./frontend-common" } frontend-common = { path = "./frontend-common" }

View file

@ -16,8 +16,8 @@ vulkan = ["frontend-common/vulkan"]
[dependencies] [dependencies]
frontend-common = { workspace = true } frontend-common = { workspace = true }
gb-emu-lib = { workspace = true } gb-emu-lib = { workspace = true }
clap = { version = "4.5.15", features = ["derive"] } clap = { version = "4.5.20", features = ["derive"] }
ctrlc = "3.4.4" ctrlc = "3.4.5"
log = { workspace = true } log = { workspace = true }
env_logger = { workspace = true } env_logger = { workspace = true }
anyhow = { version = "1.0.86", features = ["backtrace"] } anyhow = { version = "1.0.91", features = ["backtrace"] }

View file

@ -89,9 +89,7 @@ struct Args {
/// Run debug console /// Run debug console
#[arg(long)] #[arg(long)]
debug: bool, debug: bool,
// /// Use webcam as Pocket Camera emulation
// #[arg(short, long)]
// camera: bool,
/// Record frames to image sequence /// Record frames to image sequence
#[arg(long)] #[arg(long)]
record: bool, record: bool,

View file

@ -13,16 +13,16 @@ wgpu = ["gb-emu-lib/wgpu-renderer"]
[dependencies] [dependencies]
gb-emu-lib = { workspace = true } gb-emu-lib = { workspace = true }
gilrs = "0.10.9" gilrs = "0.11.0"
cpal = { version = "0.15.3", features = ["jack"] } cpal = { version = "0.15.3", features = ["jack"] }
futures = "0.3.30" futures = "0.3.31"
send_wrapper = { version = "0.6.0", optional = true } send_wrapper = { version = "0.6.0", optional = true }
winit = { version = "0.29.15", features = ["rwh_05"] } winit = { version = "0.29.15", features = ["rwh_05"] }
winit_input_helper = "0.16.0" winit_input_helper = "0.16.0"
raw-window-handle = { workspace = true } raw-window-handle = { workspace = true }
serde = { version = "1.0.205", features = ["derive"] } serde = { version = "1.0.213", features = ["derive"] }
image = { version = "0.25.2", default-features = false, features = ["png"] } image = { version = "0.25.4", default-features = false, features = ["png"] }
bytemuck = "1.16.3" bytemuck = "1.19.0"
chrono = "0.4.38" chrono = "0.4.38"
log = { workspace = true } log = { workspace = true }
anyhow = "1.0.86" anyhow = "1.0.91"

View file

@ -1,102 +0,0 @@
use gb_emu_lib::connect::PocketCamera;
use nokhwa::{
pixel_format,
utils::{CameraIndex, RequestedFormat, RequestedFormatType},
Camera,
};
use send_wrapper::SendWrapper;
pub struct Webcam {
camera: SendWrapper<Camera>,
scaled_buffer: [u8; 128 * 128],
}
impl Webcam {
pub fn new() -> Self {
let format = RequestedFormat::new::<pixel_format::RgbFormat>(
RequestedFormatType::AbsoluteHighestResolution,
);
let mut camera = SendWrapper::new(
Camera::new(CameraIndex::Index(0), format).expect("Couldn't open camera"),
);
camera
.set_frame_format(nokhwa::utils::FrameFormat::YUYV)
.expect("couldnt set frame format to yuyv");
if let Ok(formats) = camera.compatible_fourcc() {
if formats.is_empty() {
println!("no compatible frame formats listed");
}
for f in formats {
println!("compatible frame format: {f:?}");
}
} else {
println!("couldnt get frame formats")
}
println!("current camera format: {:?}", camera.camera_format());
if let Ok(formats) = camera.compatible_camera_formats() {
if formats.is_empty() {
println!("camera formats is empty");
}
for f in formats {
println!("supports camera format {f:?}");
}
} else {
println!("couldnt get camera formats");
}
Self {
camera,
scaled_buffer: [0; 128 * 128],
}
}
}
impl PocketCamera for Webcam {
fn get_image(&mut self) -> [u8; 128 * 128] {
self.scaled_buffer
}
fn begin_capture(&mut self) {
let _height = self.camera.resolution().height() as usize;
let width = self.camera.resolution().width() as usize;
// let frame = self.camera.frame_raw().expect("couldn't get frame");
self.camera
.set_frame_format(nokhwa::utils::FrameFormat::RAWRGB)
.unwrap();
let frame = self.camera.frame().expect("couldn't get frame");
println!("source format: {:?}", frame.source_frame_format());
let decoded = frame
.decode_image::<pixel_format::RgbFormat>()
.expect("couldn't decode image");
let pixels = decoded.pixels().collect::<Vec<_>>();
for y in 0..128 {
for x in 0..128 {
self.scaled_buffer[y * 128 + x] = pixels[((y * width) + x) * 2][0];
}
}
}
fn init(&mut self) {
self.camera.open_stream().expect("couldn't open stream");
self.camera
.set_frame_format(nokhwa::utils::FrameFormat::YUYV)
.unwrap();
println!(
"opened stream! current format: {:?}",
self.camera.camera_format()
);
// let format = RequestedFormat::new::<pixel_format::LumaFormat>(
// RequestedFormatType::AbsoluteHighestResolution,
// );
// self.camera
// .set_camera_requset(format)
// .expect("couldn't set format again");
}
}

View file

@ -1,8 +1,5 @@
#![feature(let_chains, if_let_guard, iter_array_chunks)] #![feature(let_chains, if_let_guard, iter_array_chunks)]
#[cfg(feature = "camera")]
use camera::Webcam;
use gb_emu_lib::{ use gb_emu_lib::{
config::{NamedConfig, CONFIG_MANAGER}, config::{NamedConfig, CONFIG_MANAGER},
connect::{ connect::{
@ -19,8 +16,6 @@ use std::{
use window::{RendererChannel, WindowManager, WindowType}; use window::{RendererChannel, WindowManager, WindowType};
pub mod audio; pub mod audio;
#[cfg(feature = "camera")]
mod camera;
pub mod debug; pub mod debug;
pub mod window; pub mod window;

View file

@ -27,8 +27,8 @@ nih_plug = { workspace = true, features = [
"vst3", "vst3",
], optional = true } ], optional = true }
baseview = { workspace = true, optional = true } baseview = { workspace = true, optional = true }
async-ringbuf = { version = "0.2.1", optional = true } async-ringbuf = { version = "0.3.1", optional = true }
futures = { version = "0.3.30", optional = true } futures = { version = "0.3.31", optional = true }
keyboard-types = { version = "0.6.2", optional = true } keyboard-types = { version = "0.7.0", optional = true }
raw-window-handle = { workspace = true } raw-window-handle = { workspace = true }
serde = { version = "1.0.205", features = ["derive"] } serde = { version = "1.0.213", features = ["derive"] }

View file

@ -69,7 +69,6 @@ impl Editor for TwincEditor {
title: String::from("gb-emu"), title: String::from("gb-emu"),
size, size,
scale: baseview::WindowScalePolicy::SystemScaleFactor, scale: baseview::WindowScalePolicy::SystemScaleFactor,
gl_config: Default::default(),
}, },
move |window| { move |window| {
let manager = Arc::new( let manager = Arc::new(

View file

@ -24,7 +24,7 @@ adw = { version = "0.7.0", package = "libadwaita", features = [
], optional = true } ], optional = true }
frontend-common = { workspace = true } frontend-common = { workspace = true }
gb-emu-lib = { workspace = true } gb-emu-lib = { workspace = true }
gtk = { version = "0.9.0", package = "gtk4", features = [ gtk = { version = "0.9.2", package = "gtk4", features = [
"v4_12", "v4_12",
], optional = true } ], optional = true }
twinc_emu_vst = { path = "../gb-vst", default-features = false } twinc_emu_vst = { path = "../gb-vst", default-features = false }
@ -33,13 +33,13 @@ cpal = "0.15.3"
log = { workspace = true } log = { workspace = true }
env_logger = { workspace = true } env_logger = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
serde = { version = "1.0.205", features = ["derive"] } serde = { version = "1.0.213", features = ["derive"] }
anyhow = "1.0.86" anyhow = "1.0.91"
[target.'cfg(any(target_os = "macos"))'.dependencies] [target.'cfg(any(target_os = "macos"))'.dependencies]
cacao = { git = "https://git.alexjanka.com/alex/cacao", optional = true } cacao = { git = "https://git.alexjanka.com/alex/cacao", optional = true }
objc = { version = "=0.3.0-beta.3", package = "objc2", optional = true } objc = { version = "0.5.2", package = "objc2", optional = true }
uuid = { version = "1.10.0", features = ["v4", "fast-rng"], optional = true } uuid = { version = "1.11.0", features = ["v4", "fast-rng"], optional = true }
[build-dependencies] [build-dependencies]
glib-build-tools = { version = "0.20.0", optional = true } glib-build-tools = { version = "0.20.0", optional = true }

View file

@ -34,12 +34,12 @@ error-colour = []
[dependencies] [dependencies]
rand = "0.8.5" rand = "0.8.5"
async-ringbuf = "0.2.1" async-ringbuf = "0.3.1"
futures = "0.3.30" futures = "0.3.31"
itertools = "0.13.0" itertools = "0.13.0"
serde = { version = "1.0.205", features = ["derive"] } serde = { version = "1.0.213", features = ["derive"] }
serde_with = "3.9.0" serde_with = "3.11.0"
bytemuck = "1.16.3" bytemuck = "1.19.0"
num-traits = "0.2.19" num-traits = "0.2.19"
pixels = { git = "https://git.alexjanka.com/alex/pixels", optional = true } pixels = { git = "https://git.alexjanka.com/alex/pixels", optional = true }
ash = { workspace = true, features = ["linked"], optional = true } ash = { workspace = true, features = ["linked"], optional = true }
@ -54,7 +54,7 @@ lazy_static = "1.5.0"
wgpu = { version = "22.1.0", optional = true } wgpu = { version = "22.1.0", optional = true }
thiserror = { workspace = true } thiserror = { workspace = true }
log = { workspace = true } log = { workspace = true }
anyhow = "1.0.86" anyhow = "1.0.91"
[build-dependencies] [build-dependencies]
naga = { version = "22.1.0", optional = true, features = [ naga = { version = "22.1.0", optional = true, features = [
@ -63,4 +63,4 @@ naga = { version = "22.1.0", optional = true, features = [
] } ] }
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies]
ash-molten = { version = "0.19.0", optional = true } ash-molten = { version = "0.20.0", optional = true }

View file

@ -2,12 +2,13 @@ use librashader_presets::ShaderPreset;
pub fn default_preset() -> ShaderPreset { pub fn default_preset() -> ShaderPreset {
ShaderPreset { ShaderPreset {
shader_count: 1, pass_count: 1,
shaders: vec![librashader_presets::ShaderPassConfig { passes: vec![librashader_presets::PassConfig {
id: 0, storage: librashader_common::StorageType::String(
name: librashader_common::ShaderStorage::String(
include_str!("./stock.slang").to_string(), include_str!("./stock.slang").to_string(),
), ),
meta: librashader_presets::PassMeta {
id: 0,
alias: None, alias: None,
filter: librashader::FilterMode::Nearest, filter: librashader::FilterMode::Nearest,
wrap_mode: librashader::WrapMode::ClampToBorder, wrap_mode: librashader::WrapMode::ClampToBorder,
@ -26,6 +27,7 @@ pub fn default_preset() -> ShaderPreset {
factor: librashader_presets::ScaleFactor::Float(1.0), factor: librashader_presets::ScaleFactor::Float(1.0),
}, },
}, },
},
}], }],
textures: vec![], textures: vec![],
parameters: vec![], parameters: vec![],

View file

@ -472,6 +472,7 @@ impl VulkanWindowInner {
size: self.swapchain.surface_resolution.into(), size: self.swapchain.surface_resolution.into(),
format: self.swapchain.format.format, format: self.swapchain.format.format,
}, },
size: self.swapchain.surface_resolution.into(),
}, },
self.vulkan_data.draw_command_buffer, self.vulkan_data.draw_command_buffer,
self.frame_counter, self.frame_counter,

View file

@ -252,6 +252,7 @@ impl RendererBackend for WgpuBackend {
filter_output.size().into(), filter_output.size().into(),
filter_output.format(), filter_output.format(),
), ),
size: filter_output.size().into(),
}, },
&mut encoder, &mut encoder,
self.frame_num, self.frame_num,

View file

@ -6,13 +6,13 @@ 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
[dependencies] [dependencies]
clap = { version = "4.5.15", features = ["derive"] } clap = { version = "4.5.20", features = ["derive"] }
strum = { version = "0.26.3", features = ["derive"] } strum = { version = "0.26.3", features = ["derive"] }
duct = "0.13.7" duct = "0.13.7"
cargo_metadata = "0.18.1" cargo_metadata = "0.18.1"
cfg-expr = "0.16.0" cfg-expr = "0.17.0"
pbr = "1.1.1" pbr = "1.1.1"
serde_json = "1.0.125" serde_json = "1.0.132"
nih_plug_xtask = { workspace = true } nih_plug_xtask = { workspace = true }
log = { workspace = true } log = { workspace = true }
env_logger = { workspace = true } env_logger = { workspace = true }

View file

@ -9,11 +9,7 @@ mod types;
static METADATA: std::sync::OnceLock<cargo_metadata::Metadata> = std::sync::OnceLock::new(); static METADATA: std::sync::OnceLock<cargo_metadata::Metadata> = std::sync::OnceLock::new();
static OUTPUT_DIR: std::sync::OnceLock<std::path::PathBuf> = std::sync::OnceLock::new(); static OUTPUT_DIR: std::sync::OnceLock<std::path::PathBuf> = std::sync::OnceLock::new();
fn executable_dir( fn executable_dir(binary: Binary, triple: impl std::fmt::Display, renderer: Renderer) -> String {
binary: Binary,
triple: &cfg_expr::targets::Triple,
renderer: Renderer,
) -> String {
format!("{}_{}_{}", binary.name(), triple, renderer.as_feature()) format!("{}_{}_{}", binary.name(), triple, renderer.as_feature())
} }
@ -298,7 +294,7 @@ fn cargo_exec(
println!("Building {package} with {renderer} renderer for target {triple}"); println!("Building {package} with {renderer} renderer for target {triple}");
let args=format!("{verb} -q -p {package} --target {triple} {release} --no-default-features -F {renderer} --message-format=json"); let args=format!("{verb} -q -p {package} --target {triple} {release} --no-default-features -F {renderer} --message-format=json-render-diagnostics");
let args = args.split_whitespace().map(|s| s.to_string()); let args = args.split_whitespace().map(|s| s.to_string());
let args = if let Some(additional_flags) = additional_flags { let args = if let Some(additional_flags) = additional_flags {
args.chain(additional_flags).collect::<Vec<_>>() args.chain(additional_flags).collect::<Vec<_>>()
@ -341,14 +337,18 @@ fn cargo_exec(
Ok( Ok(
cargo_metadata::Message::parse_stream(std::io::BufReader::new(output)).inspect(move |v| { cargo_metadata::Message::parse_stream(std::io::BufReader::new(output)).inspect(move |v| {
if let Some(pb) = pb.as_mut() {
match v { match v {
Ok(cargo_metadata::Message::BuildScriptExecuted(_)) Ok(cargo_metadata::Message::BuildScriptExecuted(_))
| Ok(cargo_metadata::Message::CompilerArtifact(_)) => { | Ok(cargo_metadata::Message::CompilerArtifact(_)) => {
if let Some(pb) = pb.as_mut() {
pb.inc(); pb.inc();
} }
_ => {}
} }
Ok(cargo_metadata::Message::CompilerMessage(message)) => {
eprintln!("{message}");
}
_ => {}
} }
}), }),
) )
@ -368,22 +368,92 @@ fn build_vst(
renderer: Renderer, renderer: Renderer,
debug: bool, debug: bool,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let triple_str = triple.map(|t| t.to_string());
let mut args = if platform == Platform::Mac { let mut args = if platform == Platform::Mac {
vec!["bundle-universal"] vec!["bundle-universal"]
} else { } else {
vec!["bundle", "--target", triple_str.as_ref().unwrap().as_str()] vec!["bundle"]
}; };
if !debug { let more_args = "twinc_emu_vst --no-default-features -F plugin";
args.push("--release");
}
let more_args = "-p twinc_emu_vst --no-default-features -F plugin";
for arg in more_args.split_whitespace() { for arg in more_args.split_whitespace() {
args.push(arg); args.push(arg);
} }
args.push("-F"); if !debug {
args.push(renderer.as_feature()); args.push("--release");
}
// we need the &str to live for this whole function
let triple_str = triple.map(|t| t.to_string());
if platform != Platform::Mac {
args.push("--target");
args.push(triple_str.as_ref().unwrap().as_str());
}
args.push("-F");
let renderer = renderer.as_feature();
args.push(renderer);
let target_dir = METADATA
.get()
.unwrap()
.target_directory
.join(format!("xtargets/{renderer}"));
std::fs::create_dir_all(&target_dir)?;
std::env::set_var("CARGO_TARGET_DIR", target_dir.as_str());
let build_plan =
nih_plug_xtask::get_build_plan("cargo xtask", args.clone().into_iter().map(String::from))?;
let mut build_plan_iter = build_plan.into_iter();
let mut pb = build_plan_iter.next().map(|(arch, num)| {
let mut pb = pbr::ProgressBar::new(num.try_into().unwrap());
if let Some(arch) = arch {
pb.message(format!("({arch}) Building crate ").as_str());
} else {
pb.message("Building crate ");
}
pb.show_time_left = false;
pb.show_speed = false;
pb
});
let args = ["xtask"]
.into_iter()
.chain(args)
.chain(["--message-format=json-render-diagnostics"])
.collect::<Vec<_>>();
// nih_plug_xtask::ch
let output = duct::cmd("cargo", args)
.env("CARGO_TARGET_DIR", target_dir)
.stdout_capture()
.stderr_capture()
.reader()?;
for v in cargo_metadata::Message::parse_stream(std::io::BufReader::new(output)) {
match v {
Ok(cargo_metadata::Message::BuildScriptExecuted(_))
| Ok(cargo_metadata::Message::CompilerArtifact(_)) => {
if pb.as_ref().is_some_and(|pb| pb.is_finish) {
pb = build_plan_iter.next().map(|(arch, num)| {
let mut pb = pbr::ProgressBar::new(num.try_into().unwrap());
if let Some(arch) = arch {
pb.message(format!("({arch}) Building crate ").as_str());
} else {
pb.message("Building crate ");
}
pb.show_time_left = false;
pb.show_speed = false;
pb
});
}
if let Some(pb) = pb.as_mut() {
pb.inc();
}
}
Ok(cargo_metadata::Message::CompilerMessage(message)) => {
eprintln!("{message}");
}
_ => {}
}
}
nih_plug_xtask::main_with_args("cargo xtask", args.into_iter().map(String::from))?;
Ok(()) Ok(())
} }