use bevy::{prelude::*, render::render_resource::Extent3d, transform::components::Transform}; use clap::{Args, Parser, Subcommand}; use studio::{ headless::{start_headless, HeadlessMode}, scene::SceneState, }; #[derive(Parser)] #[command(name = "StorytellerStudioHeadless")] #[command(author = "The Storyteller Team")] #[command(version = "1.0")] #[command( about = "Executable for Storyteller Studio Headless. Allows you to render frames to images." )] #[command(propagate_version = true)] struct StudioArgs { #[command(subcommand)] subcommand: Subcommands, } #[derive(Subcommand)] enum Subcommands { Scene { scene_dir: String, #[arg(long)] camera_motion: Option, #[arg(long)] camera_motion_speed: Option, #[arg(long, short)] output_dir: Option, #[arg(long)] skybox: Option, #[arg(long = "res", value_parser = extent3d_parser)] output_resolution: Option, #[arg(long, value_parser = clap::value_parser!(u32).range(1..))] fps: Option, #[arg(long, value_parser = clap::value_parser!(u32).range(1..))] frames: Option, }, Bvh { bvh_dir: String, #[arg(long, short = 'o', short)] out: Option, #[arg(long)] skybox: Option, #[arg(long = "res", value_parser = extent3d_parser)] output_resolution: Option, #[arg(long, value_parser = clap::value_parser!(u32).range(1..))] fps: Option, #[arg(long, value_parser = clap::value_parser!(u32).range(1..))] frames: Option, }, Mixamo { mixamo_dir: String, #[arg(long, short = 'o', short)] out: Option, #[arg(long)] skybox: Option, #[arg(long = "res", value_parser = extent3d_parser)] output_resolution: Option, #[arg(long, value_parser = clap::value_parser!(u32).range(1..))] fps: Option, #[arg(long, value_parser = clap::value_parser!(u32).range(1..))] frames: Option, }, } #[derive(Args, Clone)] struct CommonArgs {} fn main() { let args = StudioArgs::parse(); let mut app = match args.subcommand { Subcommands::Scene { scene_dir, camera_motion, camera_motion_speed, skybox, output_dir, output_resolution, fps, frames, } => { let output_dir = output_dir.unwrap_or("./screen_shots/".to_string()); let output_res = output_resolution.unwrap_or(Extent3d { width: 1280, height: 720, depth_or_array_layers: 1, }); let fps = fps.unwrap_or(24); let frames = frames.unwrap_or(30); let skybox = skybox.unwrap_or("gum_trees_4k".to_string()); let mut app = start_headless( HeadlessMode::Scene(scene_dir, skybox), fps, &output_dir, frames, output_res, ); if let Some(camera_motion) = camera_motion { let camera_motion_speed = camera_motion_speed.unwrap_or(1.0); match camera_motion.as_str() { "orbit" => { app.insert_resource(CameraMotion::Orbit(camera_motion_speed)); } "pan" => { app.insert_resource(CameraMotion::Pan(camera_motion_speed)); } "zoom" => { app.insert_resource(CameraMotion::Zoom(camera_motion_speed)); } "static" => { app.insert_resource(CameraMotion::Static); } _ => panic!("Unsupported camera motion type."), } app.add_systems( Update, update_camera_motion.run_if(in_state(SceneState::Active)), ); } app } Subcommands::Bvh { bvh_dir, skybox, out: output_dir, output_resolution, fps, frames, } => { let output_dir = output_dir.unwrap_or("./screen_shots/".to_string()); let output_res = output_resolution.unwrap_or(Extent3d { width: 1280, height: 720, depth_or_array_layers: 1, }); let fps = fps.unwrap_or(24); let frames = frames.unwrap_or(u32::MAX); let skybox = skybox.unwrap_or("gum_trees_4k".to_string()); start_headless( HeadlessMode::Bvh(bvh_dir, skybox), fps, &output_dir, frames, output_res, ) } Subcommands::Mixamo { mixamo_dir, out, skybox, output_resolution, fps, frames, } => { let output_dir = out.unwrap_or("./screen_shots/".to_string()); let output_res = output_resolution.unwrap_or(Extent3d { width: 1280, height: 720, depth_or_array_layers: 1, }); let fps = fps.unwrap_or(24); let frames = frames.unwrap_or(u32::MAX); let skybox = skybox.unwrap_or("gum_trees_4k".to_string()); start_headless( HeadlessMode::Mixamo(mixamo_dir, skybox), fps, &output_dir, frames, output_res, ) } }; app.run(); } #[derive(Resource)] enum CameraMotion { Orbit(f32), Pan(f32), Zoom(f32), Static, } pub(crate) fn update_camera_motion( mut camera: Query<&mut Transform, (With, Without)>, camera_motion: Res, time: Res