diff --git a/tools/build-wasm-example/src/main.rs b/tools/build-wasm-example/src/main.rs index 0eedf274aeb58..02a01524e1b38 100644 --- a/tools/build-wasm-example/src/main.rs +++ b/tools/build-wasm-example/src/main.rs @@ -4,7 +4,7 @@ use clap::{Parser, ValueEnum}; use xshell::{cmd, Shell}; #[derive(Debug, Copy, Clone, ValueEnum)] -enum Api { +enum WebApi { Webgl2, Webgpu, } @@ -26,9 +26,9 @@ struct Args { /// Stop after this number of frames frames: Option, - #[arg(value_enum, short, long, default_value_t = Api::Webgl2)] + #[arg(value_enum, short, long, default_value_t = WebApi::Webgl2)] /// Browser API to use for rendering - api: Api, + api: WebApi, #[arg(short, long)] /// Optimize the wasm file for size with wasm-opt @@ -50,8 +50,8 @@ fn main() { } match cli.api { - Api::Webgl2 => (), - Api::Webgpu => { + WebApi::Webgl2 => (), + WebApi::Webgpu => { features.push("animation"); features.push("bevy_asset"); features.push("bevy_audio"); @@ -95,7 +95,7 @@ fn main() { sh, "cargo build {parameters...} --profile release --target wasm32-unknown-unknown --example {example}" ); - if matches!(cli.api, Api::Webgpu) { + if matches!(cli.api, WebApi::Webgpu) { cmd = cmd.env("RUSTFLAGS", "--cfg=web_sys_unstable_apis"); } cmd.run().expect("Error building example"); diff --git a/tools/example-showcase/src/main.rs b/tools/example-showcase/src/main.rs index 226fea353095f..cd1e0084aafe7 100644 --- a/tools/example-showcase/src/main.rs +++ b/tools/example-showcase/src/main.rs @@ -1,5 +1,6 @@ use std::{ collections::HashMap, + fmt::Display, fs::{self, File}, io::Write, path::{Path, PathBuf}, @@ -8,7 +9,7 @@ use std::{ time::{Duration, Instant}, }; -use clap::Parser; +use clap::{error::ErrorKind, CommandFactory, Parser, ValueEnum}; use pbr::ProgressBar; use toml_edit::Document; use xshell::{cmd, Shell}; @@ -21,6 +22,13 @@ struct Args { #[command(subcommand)] action: Action, + #[arg(long)] + /// Pagination control - page number. To use with --per-page + page: Option, + + #[arg(long)] + /// Pagination control - number of examples per page. To use with --page + per_page: Option, } #[derive(clap::Subcommand, Debug)] @@ -44,9 +52,13 @@ enum Action { #[arg(long)] /// Path to the folder where the content should be created content_folder: String, + + #[arg(value_enum, long, default_value_t = WebApi::Webgl2)] + /// Which API to use for rendering + api: WebApi, }, - /// BUild the examples in wasm / WebGPU - BuildWebGPUExamples { + /// Build the examples in wasm + BuildWasmExamples { #[arg(long)] /// Path to the folder where the content should be created content_folder: String, @@ -58,12 +70,40 @@ enum Action { #[arg(long)] /// Optimize the wasm file for size with wasm-opt optimize_size: bool, + + #[arg(value_enum, long)] + /// Which API to use for rendering + api: WebApi, }, } +#[derive(Debug, Copy, Clone, ValueEnum)] +enum WebApi { + Webgl2, + Webgpu, +} + +impl Display for WebApi { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + WebApi::Webgl2 => write!(f, "webgl2"), + WebApi::Webgpu => write!(f, "webgpu"), + } + } +} + fn main() { let cli = Args::parse(); + if cli.page.is_none() != cli.per_page.is_none() { + let mut cmd = Args::command(); + cmd.error( + ErrorKind::MissingRequiredArgument, + "page and per-page must be used together", + ) + .exit(); + } + let profile = cli.profile; match cli.action { @@ -106,7 +146,16 @@ fn main() { } } - for to_run in examples_to_run { + let work_to_do = || { + examples_to_run + .iter() + .skip(cli.page.unwrap_or(0) * cli.per_page.unwrap_or(0)) + .take(cli.per_page.unwrap_or(usize::MAX)) + }; + + let mut pb = ProgressBar::new(work_to_do().count() as u64); + + for to_run in work_to_do() { let sh = Shell::new().unwrap(); let example = &to_run.technical_name; let extra_parameters = extra_parameters.clone(); @@ -143,7 +192,9 @@ fn main() { println!("took {duration:?}"); thread::sleep(Duration::from_secs(1)); + pb.inc(); } + pb.finish_print("done"); if failed_examples.is_empty() { println!("All examples passed!"); } else { @@ -157,7 +208,10 @@ fn main() { exit(1); } } - Action::BuildWebsiteList { content_folder } => { + Action::BuildWebsiteList { + content_folder, + api, + } => { let examples_to_run = parse_examples(); let root_path = Path::new(&content_folder); @@ -165,9 +219,10 @@ fn main() { let _ = fs::create_dir_all(root_path); let mut index = File::create(root_path.join("_index.md")).unwrap(); - index - .write_all( - "+++ + if matches!(api, WebApi::Webgpu) { + index + .write_all( + "+++ title = \"Bevy Examples in WebGPU\" template = \"examples-webgpu.html\" sort_by = \"weight\" @@ -175,9 +230,24 @@ sort_by = \"weight\" [extra] header_message = \"Examples (WebGPU)\" +++" - .as_bytes(), - ) - .unwrap(); + .as_bytes(), + ) + .unwrap(); + } else { + index + .write_all( + "+++ +title = \"Bevy Examples in WebGL2\" +template = \"examples.html\" +sort_by = \"weight\" + +[extra] +header_message = \"Examples (WebGL2)\" ++++" + .as_bytes(), + ) + .unwrap(); + } let mut categories = HashMap::new(); for to_show in examples_to_run { @@ -217,43 +287,61 @@ weight = {} format!( "+++ title = \"{}\" -template = \"example-webgpu.html\" +template = \"example{}.html\" weight = {} description = \"{}\" [extra] technical_name = \"{}\" -link = \"{}/{}\" +link = \"/examples{}/{}/{}\" image = \"../static/screenshots/{}/{}.png\" -code_path = \"content/examples-webgpu/{}\" +code_path = \"content/examples{}/{}\" github_code_path = \"{}\" -header_message = \"Examples (WebGPU)\" +header_message = \"Examples ({})\" +++", to_show.name, + match api { + WebApi::Webgpu => "-webgpu", + WebApi::Webgl2 => "", + }, categories.get(&to_show.category).unwrap(), to_show.description.replace('"', "'"), &to_show.technical_name.replace('_', "-"), + match api { + WebApi::Webgpu => "-webgpu", + WebApi::Webgl2 => "", + }, &to_show.category, &to_show.technical_name.replace('_', "-"), &to_show.category, &to_show.technical_name, + match api { + WebApi::Webgpu => "-webgpu", + WebApi::Webgl2 => "", + }, code_path .components() .skip(1) .collect::() .display(), &to_show.path, + match api { + WebApi::Webgpu => "WebGPU", + WebApi::Webgl2 => "WebGL2", + }, ) .as_bytes(), ) .unwrap(); } } - Action::BuildWebGPUExamples { + Action::BuildWasmExamples { content_folder, website_hacks, optimize_size, + api, } => { + let api = format!("{}", api); let examples_to_build = parse_examples(); let root_path = Path::new(&content_folder); @@ -282,30 +370,29 @@ header_message = \"Examples (WebGPU)\" cmd!(sh, "sed -i.bak 's/asset_folder: \"assets\"/asset_folder: \"\\/assets\\/examples\\/\"/' crates/bevy_asset/src/lib.rs").run().unwrap(); } - let mut pb = ProgressBar::new( + let work_to_do = || { examples_to_build .iter() .filter(|to_build| to_build.wasm) - .count() as u64, - ); - for to_build in examples_to_build { - if !to_build.wasm { - continue; - } + .skip(cli.page.unwrap_or(0) * cli.per_page.unwrap_or(0)) + .take(cli.per_page.unwrap_or(usize::MAX)) + }; + let mut pb = ProgressBar::new(work_to_do().count() as u64); + for to_build in work_to_do() { let sh = Shell::new().unwrap(); let example = &to_build.technical_name; if optimize_size { cmd!( sh, - "cargo run -p build-wasm-example -- --api webgpu {example} --optimize-size" + "cargo run -p build-wasm-example -- --api {api} {example} --optimize-size" ) .run() .unwrap(); } else { cmd!( sh, - "cargo run -p build-wasm-example -- --api webgpu {example}" + "cargo run -p build-wasm-example -- --api {api} {example}" ) .run() .unwrap();