2021-10-18 20:06:16 +00:00
|
|
|
use clap::Parser;
|
2020-05-05 21:33:37 +00:00
|
|
|
use image::RgbaImage;
|
2020-05-05 21:53:55 +00:00
|
|
|
use indicatif::{ProgressBar, ProgressStyle};
|
2020-05-05 13:27:10 +00:00
|
|
|
use ruffle_core::backend::audio::NullAudioBackend;
|
2020-07-08 18:26:00 +00:00
|
|
|
use ruffle_core::backend::locale::NullLocaleBackend;
|
2020-09-05 16:19:03 +00:00
|
|
|
use ruffle_core::backend::log::NullLogBackend;
|
2020-05-05 13:27:10 +00:00
|
|
|
use ruffle_core::backend::navigator::NullNavigatorBackend;
|
2020-06-15 16:53:19 +00:00
|
|
|
use ruffle_core::backend::storage::MemoryStorageBackend;
|
2020-12-15 16:39:11 +00:00
|
|
|
use ruffle_core::backend::ui::NullUiBackend;
|
2020-12-24 00:29:41 +00:00
|
|
|
use ruffle_core::backend::video::SoftwareVideoBackend;
|
2020-05-05 13:27:10 +00:00
|
|
|
use ruffle_core::tag_utils::SwfMovie;
|
|
|
|
use ruffle_core::Player;
|
2020-10-10 20:19:59 +00:00
|
|
|
use ruffle_render_wgpu::clap::{GraphicsBackend, PowerPreference};
|
2020-05-05 13:27:10 +00:00
|
|
|
use ruffle_render_wgpu::target::TextureTarget;
|
2020-10-15 23:23:36 +00:00
|
|
|
use ruffle_render_wgpu::{wgpu, Descriptors, WgpuRenderBackend};
|
2020-05-05 21:33:37 +00:00
|
|
|
use std::error::Error;
|
2020-05-05 13:27:10 +00:00
|
|
|
use std::fs::create_dir_all;
|
|
|
|
use std::path::{Path, PathBuf};
|
2020-07-23 03:18:30 +00:00
|
|
|
use std::sync::Arc;
|
2020-05-05 21:33:37 +00:00
|
|
|
use walkdir::{DirEntry, WalkDir};
|
2020-05-05 13:27:10 +00:00
|
|
|
|
2021-10-18 20:06:16 +00:00
|
|
|
#[derive(Parser, Debug, Copy, Clone)]
|
2020-06-13 19:55:55 +00:00
|
|
|
struct SizeOpt {
|
|
|
|
/// The amount to scale the page size with
|
2020-08-05 21:37:47 +00:00
|
|
|
#[clap(long = "scale", default_value = "1.0")]
|
2021-05-23 02:17:16 +00:00
|
|
|
scale: f64,
|
2020-06-13 19:55:55 +00:00
|
|
|
|
2020-09-19 14:27:24 +00:00
|
|
|
/// Optionally override the output width
|
2020-08-05 21:37:47 +00:00
|
|
|
#[clap(long = "width")]
|
2020-06-13 19:55:55 +00:00
|
|
|
width: Option<u32>,
|
|
|
|
|
2020-09-19 14:27:24 +00:00
|
|
|
/// Optionally override the output height
|
2020-08-05 21:37:47 +00:00
|
|
|
#[clap(long = "height")]
|
2020-06-13 19:55:55 +00:00
|
|
|
height: Option<u32>,
|
|
|
|
}
|
|
|
|
|
2021-10-18 20:06:16 +00:00
|
|
|
#[derive(Parser, Debug)]
|
2020-08-05 21:37:47 +00:00
|
|
|
#[clap(name = "Ruffle Exporter", author, version)]
|
2020-05-05 13:27:10 +00:00
|
|
|
struct Opt {
|
2020-05-05 21:33:37 +00:00
|
|
|
/// The file or directory of files to export frames from
|
2020-08-05 21:37:47 +00:00
|
|
|
#[clap(name = "swf", parse(from_os_str))]
|
2020-05-05 13:27:10 +00:00
|
|
|
swf: PathBuf,
|
|
|
|
|
2020-05-05 21:33:37 +00:00
|
|
|
/// The file or directory (if multiple frames/files) to store the capture in.
|
|
|
|
/// The default value will either be:
|
|
|
|
/// - If given one swf and one frame, the name of the swf + ".png"
|
|
|
|
/// - If given one swf and multiple frames, the name of the swf as a directory
|
|
|
|
/// - If given multiple swfs, this field is required.
|
2020-08-05 21:37:47 +00:00
|
|
|
#[clap(name = "output", parse(from_os_str))]
|
2020-05-05 13:27:10 +00:00
|
|
|
output_path: Option<PathBuf>,
|
|
|
|
|
2020-05-05 21:33:37 +00:00
|
|
|
/// Number of frames to capture per file
|
2020-09-22 01:56:46 +00:00
|
|
|
#[clap(short = 'f', long = "frames", default_value = "1")]
|
2020-05-05 13:27:10 +00:00
|
|
|
frames: u32,
|
2020-05-05 21:53:55 +00:00
|
|
|
|
2020-05-22 15:58:51 +00:00
|
|
|
/// Number of frames to skip
|
2020-08-05 21:37:47 +00:00
|
|
|
#[clap(long = "skipframes", default_value = "0")]
|
2020-05-22 15:58:51 +00:00
|
|
|
skipframes: u32,
|
|
|
|
|
2020-05-05 21:53:55 +00:00
|
|
|
/// Don't show a progress bar
|
2020-08-05 21:37:47 +00:00
|
|
|
#[clap(short, long)]
|
2020-05-05 21:53:55 +00:00
|
|
|
silent: bool,
|
2020-06-13 19:55:55 +00:00
|
|
|
|
2020-08-05 21:37:47 +00:00
|
|
|
#[clap(flatten)]
|
2020-06-13 19:55:55 +00:00
|
|
|
size: SizeOpt,
|
2020-10-10 20:19:59 +00:00
|
|
|
|
|
|
|
/// Type of graphics backend to use. Not all options may be supported by your current system.
|
|
|
|
/// Default will attempt to pick the most supported graphics backend.
|
|
|
|
#[clap(
|
|
|
|
long,
|
|
|
|
short,
|
|
|
|
case_insensitive = true,
|
|
|
|
default_value = "default",
|
|
|
|
arg_enum
|
|
|
|
)]
|
|
|
|
graphics: GraphicsBackend,
|
|
|
|
|
|
|
|
/// Power preference for the graphics device used. High power usage tends to prefer dedicated GPUs,
|
|
|
|
/// whereas a low power usage tends prefer integrated GPUs.
|
2020-10-14 20:28:37 +00:00
|
|
|
#[clap(long, short, case_insensitive = true, default_value = "high", arg_enum)]
|
2020-10-10 20:19:59 +00:00
|
|
|
power: PowerPreference,
|
2020-10-14 20:06:36 +00:00
|
|
|
|
|
|
|
/// Location to store a wgpu trace output
|
|
|
|
#[clap(long, parse(from_os_str))]
|
|
|
|
#[cfg(feature = "render_trace")]
|
|
|
|
trace_path: Option<PathBuf>,
|
2020-05-05 13:27:10 +00:00
|
|
|
}
|
|
|
|
|
2020-05-05 21:33:37 +00:00
|
|
|
fn take_screenshot(
|
2020-10-15 23:23:36 +00:00
|
|
|
descriptors: Descriptors,
|
2020-05-05 21:33:37 +00:00
|
|
|
swf_path: &Path,
|
2020-05-05 13:27:10 +00:00
|
|
|
frames: u32,
|
2020-05-22 15:58:51 +00:00
|
|
|
skipframes: u32,
|
2020-05-05 21:53:55 +00:00
|
|
|
progress: &Option<ProgressBar>,
|
2020-06-13 19:55:55 +00:00
|
|
|
size: SizeOpt,
|
2020-10-15 23:23:36 +00:00
|
|
|
) -> Result<(Descriptors, Vec<RgbaImage>), Box<dyn std::error::Error>> {
|
2021-03-22 23:41:40 +00:00
|
|
|
let movie = SwfMovie::from_path(&swf_path, None)?;
|
2020-05-05 13:27:10 +00:00
|
|
|
|
2021-05-23 02:17:16 +00:00
|
|
|
let width = size
|
|
|
|
.width
|
|
|
|
.map(f64::from)
|
|
|
|
.unwrap_or_else(|| movie.width().to_pixels());
|
|
|
|
let width = (width * size.scale).round() as u32;
|
|
|
|
|
|
|
|
let height = size
|
|
|
|
.height
|
|
|
|
.map(f64::from)
|
|
|
|
.unwrap_or_else(|| movie.height().to_pixels());
|
|
|
|
let height = (height * size.scale).round() as u32;
|
2020-06-13 19:55:55 +00:00
|
|
|
|
2020-10-15 23:23:36 +00:00
|
|
|
let target = TextureTarget::new(&descriptors.device, (width, height));
|
2020-05-05 13:27:10 +00:00
|
|
|
let player = Player::new(
|
2020-10-15 23:23:36 +00:00
|
|
|
Box::new(WgpuRenderBackend::new(descriptors, target)?),
|
2020-05-05 13:27:10 +00:00
|
|
|
Box::new(NullAudioBackend::new()),
|
|
|
|
Box::new(NullNavigatorBackend::new()),
|
2020-06-15 16:53:19 +00:00
|
|
|
Box::new(MemoryStorageBackend::default()),
|
2020-07-08 18:26:00 +00:00
|
|
|
Box::new(NullLocaleBackend::new()),
|
2020-12-24 00:29:41 +00:00
|
|
|
Box::new(SoftwareVideoBackend::new()),
|
2020-09-05 16:19:03 +00:00
|
|
|
Box::new(NullLogBackend::new()),
|
2020-12-15 16:39:11 +00:00
|
|
|
Box::new(NullUiBackend::new()),
|
2020-05-05 13:27:10 +00:00
|
|
|
)?;
|
|
|
|
|
2020-06-13 19:55:55 +00:00
|
|
|
player
|
|
|
|
.lock()
|
|
|
|
.unwrap()
|
2021-04-19 23:22:11 +00:00
|
|
|
.set_viewport_dimensions(width, height, size.scale as f64);
|
2020-07-23 03:18:30 +00:00
|
|
|
player.lock().unwrap().set_root_movie(Arc::new(movie));
|
2020-06-13 19:55:55 +00:00
|
|
|
|
2020-05-05 21:33:37 +00:00
|
|
|
let mut result = Vec::new();
|
2020-05-22 15:58:51 +00:00
|
|
|
let totalframes = frames + skipframes;
|
|
|
|
|
|
|
|
for i in 0..totalframes {
|
2020-05-05 21:53:55 +00:00
|
|
|
if let Some(progress) = &progress {
|
2021-05-03 08:44:15 +00:00
|
|
|
progress.set_message(format!(
|
2020-05-05 21:53:55 +00:00
|
|
|
"{} frame {}",
|
|
|
|
swf_path.file_stem().unwrap().to_string_lossy(),
|
|
|
|
i
|
|
|
|
));
|
|
|
|
}
|
2020-05-05 13:27:10 +00:00
|
|
|
player.lock().unwrap().run_frame();
|
2020-05-22 15:58:51 +00:00
|
|
|
if i >= skipframes {
|
|
|
|
player.lock().unwrap().render();
|
|
|
|
let mut player = player.lock().unwrap();
|
|
|
|
let renderer = player
|
|
|
|
.renderer_mut()
|
|
|
|
.downcast_mut::<WgpuRenderBackend<TextureTarget>>()
|
|
|
|
.unwrap();
|
|
|
|
let target = renderer.target();
|
|
|
|
if let Some(image) = target.capture(renderer.device()) {
|
|
|
|
result.push(image);
|
|
|
|
} else {
|
|
|
|
return Err(format!("Unable to capture frame {} of {:?}", i, swf_path).into());
|
|
|
|
}
|
2020-05-05 13:27:10 +00:00
|
|
|
}
|
2020-05-05 21:53:55 +00:00
|
|
|
|
|
|
|
if let Some(progress) = &progress {
|
|
|
|
progress.inc(1);
|
|
|
|
}
|
2020-05-05 13:27:10 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 23:23:36 +00:00
|
|
|
let descriptors = Arc::try_unwrap(player)
|
|
|
|
.ok()
|
|
|
|
.unwrap()
|
|
|
|
.into_inner()?
|
|
|
|
.destroy()
|
|
|
|
.downcast::<WgpuRenderBackend<TextureTarget>>()
|
|
|
|
.ok()
|
|
|
|
.unwrap()
|
|
|
|
.descriptors();
|
|
|
|
Ok((descriptors, result))
|
2020-05-05 13:27:10 +00:00
|
|
|
}
|
|
|
|
|
2020-05-05 21:53:55 +00:00
|
|
|
fn find_files(root: &Path, with_progress: bool) -> Vec<DirEntry> {
|
|
|
|
let progress = if with_progress {
|
|
|
|
Some(ProgressBar::new_spinner())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2020-05-05 21:33:37 +00:00
|
|
|
let mut results = Vec::new();
|
|
|
|
|
|
|
|
for entry in WalkDir::new(root)
|
|
|
|
.follow_links(true)
|
|
|
|
.into_iter()
|
|
|
|
.filter_map(|e| e.ok())
|
|
|
|
{
|
|
|
|
let f_name = entry.file_name().to_string_lossy();
|
|
|
|
|
|
|
|
if f_name.ends_with(".swf") {
|
|
|
|
results.push(entry);
|
2020-05-05 21:53:55 +00:00
|
|
|
if let Some(progress) = &progress {
|
2021-05-03 08:44:15 +00:00
|
|
|
progress.set_message(format!("Searching for swf files... {}", results.len()));
|
2020-05-05 21:53:55 +00:00
|
|
|
}
|
2020-05-05 21:33:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-05 21:53:55 +00:00
|
|
|
if let Some(progress) = &progress {
|
2021-05-03 08:44:15 +00:00
|
|
|
progress.finish_with_message(format!("Found {} swf files to export", results.len()));
|
2020-05-05 21:53:55 +00:00
|
|
|
}
|
|
|
|
|
2020-05-05 21:33:37 +00:00
|
|
|
results
|
|
|
|
}
|
|
|
|
|
2020-10-15 23:23:36 +00:00
|
|
|
fn capture_single_swf(descriptors: Descriptors, opt: &Opt) -> Result<(), Box<dyn Error>> {
|
2020-06-13 19:55:55 +00:00
|
|
|
let output = opt.output_path.clone().unwrap_or_else(|| {
|
2020-05-05 13:27:10 +00:00
|
|
|
let mut result = PathBuf::new();
|
2021-04-15 04:55:06 +00:00
|
|
|
result.set_file_name(opt.swf.file_stem().unwrap());
|
2020-06-13 19:55:55 +00:00
|
|
|
if opt.frames == 1 {
|
2020-05-05 13:27:10 +00:00
|
|
|
result.set_extension("png");
|
|
|
|
}
|
|
|
|
result
|
|
|
|
});
|
2020-05-05 21:33:37 +00:00
|
|
|
|
2020-06-13 19:55:55 +00:00
|
|
|
if opt.frames > 1 {
|
2020-05-05 13:27:10 +00:00
|
|
|
let _ = create_dir_all(&output);
|
|
|
|
}
|
2020-05-05 21:33:37 +00:00
|
|
|
|
2020-06-13 19:55:55 +00:00
|
|
|
let progress = if !opt.silent {
|
|
|
|
let progress = ProgressBar::new(opt.frames as u64);
|
2020-05-05 21:53:55 +00:00
|
|
|
progress.set_style(
|
|
|
|
ProgressStyle::default_bar()
|
|
|
|
.template(
|
|
|
|
"[{elapsed_precise}] {bar:40.cyan/blue} [{eta_precise}] {pos:>7}/{len:7} {msg}",
|
|
|
|
)
|
|
|
|
.progress_chars("##-"),
|
|
|
|
);
|
|
|
|
Some(progress)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2020-10-15 23:23:36 +00:00
|
|
|
let (_, frames) = take_screenshot(
|
|
|
|
descriptors,
|
2020-06-13 19:55:55 +00:00
|
|
|
&opt.swf,
|
|
|
|
opt.frames,
|
|
|
|
opt.skipframes,
|
|
|
|
&progress,
|
|
|
|
opt.size,
|
|
|
|
)?;
|
2020-05-05 21:53:55 +00:00
|
|
|
|
|
|
|
if let Some(progress) = &progress {
|
2021-05-03 08:44:15 +00:00
|
|
|
progress.set_message(opt.swf.file_stem().unwrap().to_string_lossy().into_owned());
|
2020-05-05 21:53:55 +00:00
|
|
|
}
|
2020-05-05 21:33:37 +00:00
|
|
|
|
|
|
|
if frames.len() == 1 {
|
|
|
|
frames.get(0).unwrap().save(&output)?;
|
|
|
|
} else {
|
|
|
|
for (frame, image) in frames.iter().enumerate() {
|
2021-06-22 10:04:27 +00:00
|
|
|
let mut path: PathBuf = (&output).into();
|
2020-05-05 21:33:37 +00:00
|
|
|
path.push(format!("{}.png", frame));
|
|
|
|
image.save(&path)?;
|
2020-05-05 13:27:10 +00:00
|
|
|
}
|
2020-05-05 21:53:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let message = if frames.len() == 1 {
|
|
|
|
format!(
|
|
|
|
"Saved first frame of {} to {}",
|
2020-06-13 19:55:55 +00:00
|
|
|
opt.swf.to_string_lossy(),
|
2020-05-05 21:53:55 +00:00
|
|
|
output.to_string_lossy()
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
format!(
|
2020-05-05 21:33:37 +00:00
|
|
|
"Saved first {} frames of {} to {}",
|
|
|
|
frames.len(),
|
2020-06-13 19:55:55 +00:00
|
|
|
opt.swf.to_string_lossy(),
|
2020-05-05 21:33:37 +00:00
|
|
|
output.to_string_lossy()
|
2020-05-05 21:53:55 +00:00
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(progress) = progress {
|
2021-05-03 08:44:15 +00:00
|
|
|
progress.finish_with_message(message);
|
2020-05-05 21:53:55 +00:00
|
|
|
} else {
|
|
|
|
println!("{}", message);
|
2020-05-05 21:33:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-04-15 04:55:06 +00:00
|
|
|
#[allow(unknown_lints, clippy::branches_sharing_code)]
|
2020-10-15 23:23:36 +00:00
|
|
|
fn capture_multiple_swfs(mut descriptors: Descriptors, opt: &Opt) -> Result<(), Box<dyn Error>> {
|
2020-06-13 19:55:55 +00:00
|
|
|
let output = opt.output_path.clone().unwrap();
|
|
|
|
let files = find_files(&opt.swf, !opt.silent);
|
2020-05-05 21:53:55 +00:00
|
|
|
|
2020-06-13 19:55:55 +00:00
|
|
|
let progress = if !opt.silent {
|
|
|
|
let progress = ProgressBar::new((files.len() as u64) * (opt.frames as u64));
|
2020-05-05 21:53:55 +00:00
|
|
|
progress.set_style(
|
|
|
|
ProgressStyle::default_bar()
|
|
|
|
.template(
|
|
|
|
"[{elapsed_precise}] {bar:40.cyan/blue} [{eta_precise}] {pos:>7}/{len:7} {msg}",
|
|
|
|
)
|
|
|
|
.progress_chars("##-"),
|
|
|
|
);
|
|
|
|
Some(progress)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2020-05-05 21:33:37 +00:00
|
|
|
|
|
|
|
for file in &files {
|
2020-10-15 23:23:36 +00:00
|
|
|
let (new_descriptors, frames) = take_screenshot(
|
|
|
|
descriptors,
|
2021-06-05 10:53:23 +00:00
|
|
|
file.path(),
|
2020-06-13 19:55:55 +00:00
|
|
|
opt.frames,
|
|
|
|
opt.skipframes,
|
2020-05-05 22:17:01 +00:00
|
|
|
&progress,
|
2020-06-13 19:55:55 +00:00
|
|
|
opt.size,
|
2020-05-05 22:17:01 +00:00
|
|
|
)?;
|
2020-10-15 23:23:36 +00:00
|
|
|
descriptors = new_descriptors;
|
2020-05-05 21:53:55 +00:00
|
|
|
|
|
|
|
if let Some(progress) = &progress {
|
2021-05-03 08:44:15 +00:00
|
|
|
progress.set_message(
|
|
|
|
file.path()
|
|
|
|
.file_stem()
|
|
|
|
.unwrap()
|
|
|
|
.to_string_lossy()
|
|
|
|
.into_owned(),
|
|
|
|
);
|
2020-05-05 21:53:55 +00:00
|
|
|
}
|
|
|
|
|
2020-05-05 21:33:37 +00:00
|
|
|
let mut relative_path = file
|
|
|
|
.path()
|
2020-06-13 19:55:55 +00:00
|
|
|
.strip_prefix(&opt.swf)
|
2021-06-05 10:53:23 +00:00
|
|
|
.unwrap_or_else(|_| file.path())
|
2020-05-05 21:33:37 +00:00
|
|
|
.to_path_buf();
|
|
|
|
|
|
|
|
if frames.len() == 1 {
|
2021-06-22 10:04:27 +00:00
|
|
|
let mut destination: PathBuf = (&output).into();
|
2020-05-05 21:33:37 +00:00
|
|
|
relative_path.set_extension("png");
|
|
|
|
destination.push(relative_path);
|
|
|
|
if let Some(parent) = destination.parent() {
|
|
|
|
let _ = create_dir_all(parent);
|
|
|
|
}
|
|
|
|
frames.get(0).unwrap().save(&destination)?;
|
|
|
|
} else {
|
2021-06-22 10:04:27 +00:00
|
|
|
let mut parent: PathBuf = (&output).into();
|
2020-05-05 21:33:37 +00:00
|
|
|
relative_path.set_extension("");
|
|
|
|
parent.push(&relative_path);
|
|
|
|
let _ = create_dir_all(&parent);
|
|
|
|
for (frame, image) in frames.iter().enumerate() {
|
|
|
|
let mut destination = parent.clone();
|
|
|
|
destination.push(format!("{}.png", frame));
|
|
|
|
image.save(&destination)?;
|
|
|
|
}
|
2020-05-05 13:27:10 +00:00
|
|
|
}
|
|
|
|
}
|
2020-05-05 21:33:37 +00:00
|
|
|
|
2020-06-13 19:55:55 +00:00
|
|
|
let message = if opt.frames == 1 {
|
2020-05-05 21:53:55 +00:00
|
|
|
format!(
|
2020-05-05 21:33:37 +00:00
|
|
|
"Saved first frame of {} files to {}",
|
|
|
|
files.len(),
|
|
|
|
output.to_string_lossy()
|
2020-05-05 21:53:55 +00:00
|
|
|
)
|
2020-05-05 21:33:37 +00:00
|
|
|
} else {
|
2020-05-05 21:53:55 +00:00
|
|
|
format!(
|
2020-05-05 21:33:37 +00:00
|
|
|
"Saved first {} frames of {} files to {}",
|
2020-06-13 19:55:55 +00:00
|
|
|
opt.frames,
|
2020-05-05 21:33:37 +00:00
|
|
|
files.len(),
|
|
|
|
output.to_string_lossy()
|
2020-05-05 21:53:55 +00:00
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(progress) = progress {
|
2021-05-03 08:44:15 +00:00
|
|
|
progress.finish_with_message(message);
|
2020-05-05 21:53:55 +00:00
|
|
|
} else {
|
|
|
|
println!("{}", message);
|
2020-05-05 21:33:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-10-14 20:06:36 +00:00
|
|
|
#[cfg(feature = "render_trace")]
|
|
|
|
fn trace_path(opt: &Opt) -> Option<&Path> {
|
|
|
|
if let Some(path) = &opt.trace_path {
|
|
|
|
let _ = std::fs::create_dir_all(path);
|
|
|
|
Some(path)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(feature = "render_trace"))]
|
|
|
|
fn trace_path(_opt: &Opt) -> Option<&Path> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2020-05-05 21:33:37 +00:00
|
|
|
fn main() -> Result<(), Box<dyn Error>> {
|
2020-08-05 21:37:47 +00:00
|
|
|
let opt: Opt = Opt::parse();
|
2020-10-10 20:19:59 +00:00
|
|
|
let instance = wgpu::Instance::new(opt.graphics.into());
|
2021-09-08 23:40:51 +00:00
|
|
|
let descriptors =
|
|
|
|
futures::executor::block_on(WgpuRenderBackend::<TextureTarget>::build_descriptors(
|
|
|
|
opt.graphics.into(),
|
|
|
|
instance,
|
|
|
|
None,
|
|
|
|
opt.power.into(),
|
|
|
|
trace_path(&opt),
|
|
|
|
))?;
|
2020-05-05 22:17:01 +00:00
|
|
|
|
2020-05-05 21:33:37 +00:00
|
|
|
if opt.swf.is_file() {
|
2020-10-15 23:23:36 +00:00
|
|
|
capture_single_swf(descriptors, &opt)?;
|
2020-06-13 19:55:55 +00:00
|
|
|
} else if opt.output_path.is_some() {
|
2020-10-15 23:23:36 +00:00
|
|
|
capture_multiple_swfs(descriptors, &opt)?;
|
2020-05-05 21:33:37 +00:00
|
|
|
} else {
|
|
|
|
return Err("Output directory is required when exporting multiple files.".into());
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
2020-05-05 13:27:10 +00:00
|
|
|
}
|