This repository has no description
1pub mod new;
2pub mod run;
3pub mod watch;
4
5use crate::{enabled_features, Canvas, ColorMapping};
6use docopt::Docopt;
7use measure_time::debug_time;
8use serde::Deserialize;
9
10const USAGE: &str = "
11▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
12█░▄▄█░████░▄▄▀█▀▄▄▀█░▄▄█░▄▀▄░█░▄▄▀█░█▀█░▄▄█░▄▄▀█
13█▄▄▀█░▄▄░█░▀▀░█░▀▀░█░▄▄█░█▄█░█░▀▀░█░▄▀█░▄▄█░▀▀▄█
14█▄▄▄█▄██▄█▄██▄█░████▄▄▄█▄███▄█▄██▄█▄█▄█▄▄▄█▄█▄▄█
15▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀v?.?.?▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
16
17Enabled features:
18
19Usage: shapemaker test-video [options] [--color <mapping>...] <file>
20 shapemaker beacon start [options] [--color <mapping>...] <file>
21 shapemaker beacon ping
22 shapemaker examples (dna-analysis-machine|shapeshed|colors-shed|grid) [options] <file>
23 shapemaker new <name>
24 shapemaker watch [<directory>]
25 shapemaker --help
26 shapemaker --version
27
28Options:
29 --resolution <pixelcount> Size of the image (or frames)'s largest dimension in pixels [default: 1000]
30 --colors <file> JSON file mapping color names to hex values
31 The supported color names are: black, white, red, green, blue, yellow, orange, purple, brown, pink, gray, and cyan.
32 -c --color <mapping> Color mapping in the form of <color>:<hex>. Can be used multiple times.
33 --grid-size <WIDTHxHEIGHT> Size of the grid (number of anchor points) [default: 3x3]
34 Putting one of the dimensions to 1 can cause a crash.
35 --cell-size <size> Size of a cell in pixels [default: 50]
36 --canvas-padding <size> Outter canvas padding between cells in pixels [default: 10]
37 --line-width <size> Width of the lines in pixels [default: 2]
38 --small-circle-radius <size> Radius of small circles in pixels [default: 5]
39 --dot-radius <size> Radius of dots in pixels [default: 2]
40 --empty-shape-stroke <size> Width of the stroke when a closed shape is not filled [default: 0.5]
41 --render-grid Render the grid of anchor points
42 --objects-count <range> Number of objects to render [default: 3..6]
43 --polygon-vertices <range> Number of vertices for polygons [default: 2..6]
44
45 Note: <range>s are inclusive on both ends
46
47 Video-specific:
48 --workers <number> Number of parallel threads to use for rendering [default: 8]
49 --fps <fps> Frames per second [default: 30]
50 --audio <file> Audio file to use for the video
51 --duration <seconds> Number of seconds to render. If not set, the video will be as long as the audio file.
52 --start <seconds> Start the video at this time in seconds. [default: 0]
53 --sync-with <directory> Directory containing the audio files to sync to.
54 The directory must contain:
55 - stems/(instrument name).wav — stems
56 - landmarks.json — JSON file mapping time in milliseconds to marker text (see ./landmarks.py)
57 - full.mp3 — the complete audio file to use as the video's audio
58 - bpm.txt — the BPM of the audio file (see ./landmarks.py)
59
60
61";
62
63pub fn cli_args() -> Args {
64 let args: Args =
65 Docopt::new(USAGE.replace("?.?.?", env!("CARGO_PKG_VERSION")).replace(
66 "Enabled features:",
67 &format!("Enabled features: {:?}", enabled_features()),
68 ))
69 .and_then(|d| d.deserialize())
70 .unwrap_or_else(|e| e.exit());
71
72 if args.flag_version {
73 println!(
74 "shapemaker {}\nenabled features: {:?}",
75 env!("CARGO_PKG_VERSION"),
76 enabled_features()
77 );
78 std::process::exit(0);
79 }
80
81 args
82}
83
84pub fn canvas_from_cli(args: &Args) -> Canvas {
85 debug_time!("canvas_from_cli");
86 let mut canvas = Canvas::with_layers(vec![]);
87 canvas.colormap = load_colormap(args);
88 set_canvas_settings_from_args(args, &mut canvas);
89 canvas
90}
91
92#[derive(Debug, Deserialize)]
93pub struct Args {
94 pub cmd_test_video: bool,
95 pub cmd_beacon: bool,
96 pub cmd_start: bool,
97 pub cmd_new: bool,
98 pub cmd_watch: bool,
99 pub cmd_ping: bool,
100 pub arg_directory: String,
101 pub arg_name: String,
102 pub arg_file: String,
103 pub flag_version: bool,
104 pub flag_color: Vec<String>,
105 pub flag_colors: Option<String>,
106 pub flag_grid_size: Option<String>,
107 pub flag_cell_size: Option<usize>,
108 pub flag_canvas_padding: Option<usize>,
109 pub flag_line_width: Option<f32>,
110 pub flag_small_circle_radius: Option<f32>,
111 pub flag_dot_radius: Option<f32>,
112 pub flag_empty_shape_stroke: Option<f32>,
113 pub flag_render_grid: bool,
114 pub flag_objects_count: Option<String>,
115 pub flag_polygon_vertices: Option<String>,
116 pub flag_fps: Option<usize>,
117 pub flag_sync_with: Option<String>,
118 pub flag_audio: Option<String>,
119 pub flag_resolution: Option<u32>,
120 pub flag_workers: Option<usize>,
121 pub flag_duration: Option<usize>,
122 pub flag_start: Option<usize>,
123}
124
125fn set_canvas_settings_from_args(args: &Args, canvas: &mut Canvas) {
126 if let Some(dimensions) = &args.flag_grid_size {
127 let mut split = dimensions.split('x');
128 let width = split.next().unwrap().parse::<usize>().unwrap();
129 let height = split.next().unwrap().parse::<usize>().unwrap();
130 canvas.set_grid_size(width, height);
131 }
132 if let Some(cell_size) = args.flag_cell_size {
133 canvas.cell_size = cell_size;
134 }
135 if let Some(canvas_padding) = args.flag_canvas_padding {
136 canvas.canvas_outer_padding = canvas_padding;
137 }
138 if let Some(line_width) = args.flag_line_width {
139 canvas.object_sizes.default_line_width = line_width;
140 }
141 if let Some(small_circle_radius) = args.flag_small_circle_radius {
142 canvas.object_sizes.small_circle_radius = small_circle_radius;
143 }
144 if let Some(dot_radius) = args.flag_dot_radius {
145 canvas.object_sizes.dot_radius = dot_radius;
146 }
147 if let Some(empty_shape_stroke) = args.flag_empty_shape_stroke {
148 canvas.object_sizes.empty_shape_stroke_width = empty_shape_stroke;
149 }
150 if let Some(objects_count) = &args.flag_objects_count {
151 let mut split = objects_count.split("..");
152 let min = split.next().unwrap().parse::<usize>().unwrap();
153 let max = split.next().unwrap().parse::<usize>().unwrap();
154 // +1 because the range is exclusive, using ..= raises a type error
155 canvas.objects_count_range = min..(max + 1);
156 }
157 if let Some(polygon_vertices) = &args.flag_polygon_vertices {
158 let mut split = polygon_vertices.split("..");
159 let min = split.next().unwrap().parse::<usize>().unwrap();
160 let max = split.next().unwrap().parse::<usize>().unwrap();
161 canvas.polygon_vertices_range = min..(max + 1);
162 }
163}
164
165fn load_colormap(args: &Args) -> ColorMapping {
166 if let Some(file) = &args.flag_colors {
167 ColorMapping::from_file(file.into())
168 } else {
169 ColorMapping::from_cli_args(&args.flag_color)
170 }
171}