mirror of https://github.com/Leinnan/rpack.git
CLI commands
This commit is contained in:
parent
e93aa6a674
commit
e5781c912d
|
|
@ -4,3 +4,4 @@
|
||||||
/dist
|
/dist
|
||||||
skyline-packer-output.png
|
skyline-packer-output.png
|
||||||
result.png
|
result.png
|
||||||
|
Cargo.lock
|
||||||
|
|
|
||||||
|
|
@ -4674,6 +4674,7 @@ dependencies = [
|
||||||
name = "rpack_cli"
|
name = "rpack_cli"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"basis-universal",
|
"basis-universal",
|
||||||
"bevy_rpack",
|
"bevy_rpack",
|
||||||
"clap",
|
"clap",
|
||||||
|
|
@ -4683,6 +4684,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"texture_packer",
|
"texture_packer",
|
||||||
|
"thiserror 2.0.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ bevy = { version = "0.15", optional = true, default-features = false, features =
|
||||||
"bevy_ui",
|
"bevy_ui",
|
||||||
] }
|
] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1"
|
||||||
thiserror = "2.0"
|
thiserror = "2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
bevy = { version = "0.15", default-features = false, features = [
|
bevy = { version = "0.15", default-features = false, features = [
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ impl RpackAssetHelper for RpackAtlasAsset {
|
||||||
},
|
},
|
||||||
self.image.clone(),
|
self.image.clone(),
|
||||||
)),
|
)),
|
||||||
None => Err(RpackAtlasError::WrongKey),
|
_ => Err(RpackAtlasError::WrongKey),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,3 +22,5 @@ clap = { version = "4", features = ["derive"], optional = true }
|
||||||
basis-universal = { version = "0.3.1", optional = true }
|
basis-universal = { version = "0.3.1", optional = true }
|
||||||
image_dds = { version = "0.6.2", optional = true }
|
image_dds = { version = "0.6.2", optional = true }
|
||||||
glob = { version = "0.3", optional = true }
|
glob = { version = "0.3", optional = true }
|
||||||
|
anyhow = "1"
|
||||||
|
thiserror = "2"
|
||||||
|
|
@ -0,0 +1,201 @@
|
||||||
|
use std::{io::Write, path::Path};
|
||||||
|
|
||||||
|
use clap::Subcommand;
|
||||||
|
use rpack_cli::{ImageFile, Spritesheet, TilemapGenerationConfig};
|
||||||
|
|
||||||
|
use rpack_cli::SaveImageFormat;
|
||||||
|
|
||||||
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
|
pub enum Commands {
|
||||||
|
/// Generates a tilemap
|
||||||
|
Generate {
|
||||||
|
/// Name of the tilemap to build, when no value is provided uses 'tilemap'
|
||||||
|
#[clap(action)]
|
||||||
|
name: Option<String>,
|
||||||
|
/// size of the tilemap, default: 512
|
||||||
|
#[arg(long)]
|
||||||
|
size: Option<u32>,
|
||||||
|
/// Image format
|
||||||
|
#[clap(short, long)]
|
||||||
|
format: Option<SaveImageFormat>,
|
||||||
|
},
|
||||||
|
/// Creates a tilemap generation config that can be used by this tool
|
||||||
|
ConfigCreate {
|
||||||
|
/// path of the config to create
|
||||||
|
#[clap(action)]
|
||||||
|
config_path: String,
|
||||||
|
/// path of the tilemap to build, when no value is provided uses '/tilemap'
|
||||||
|
#[clap(long)]
|
||||||
|
output_path: Option<String>,
|
||||||
|
/// size of the tilemap, default: 512
|
||||||
|
#[arg(long)]
|
||||||
|
size: Option<u32>,
|
||||||
|
/// Image format, png by default
|
||||||
|
#[clap(short, long)]
|
||||||
|
format: Option<SaveImageFormat>,
|
||||||
|
/// Asset sources path, argument can be passed multiple times
|
||||||
|
#[clap(short, long)]
|
||||||
|
source_paths: Vec<String>,
|
||||||
|
},
|
||||||
|
/// Generates a tilemap from config
|
||||||
|
GenerateFromConfig {
|
||||||
|
/// path of the config to use
|
||||||
|
#[clap(action)]
|
||||||
|
config_path: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
impl Commands {
|
||||||
|
pub(crate) fn run(&self) -> anyhow::Result<()> {
|
||||||
|
match self.clone() {
|
||||||
|
Commands::Generate { name, size, format } => Self::generate_tilemap(name, size, format),
|
||||||
|
Commands::ConfigCreate {
|
||||||
|
config_path,
|
||||||
|
output_path,
|
||||||
|
size,
|
||||||
|
format,
|
||||||
|
source_paths,
|
||||||
|
} => Self::create_config(config_path, output_path, size, format, source_paths),
|
||||||
|
Commands::GenerateFromConfig { config_path } => {
|
||||||
|
Self::generate_tilemap_from_config(config_path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_tilemap(
|
||||||
|
name: Option<String>,
|
||||||
|
size: Option<u32>,
|
||||||
|
format: Option<SaveImageFormat>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let name = name.unwrap_or("tilemap".to_owned());
|
||||||
|
let format = format.unwrap_or_default();
|
||||||
|
let atlas_filename = format!("{}{}", name, format);
|
||||||
|
let atlas_json_filename = format!("{}.rpack.json", name);
|
||||||
|
let size = size.unwrap_or(512);
|
||||||
|
|
||||||
|
let images: Vec<ImageFile> = glob::glob("**/*png")?
|
||||||
|
.flatten()
|
||||||
|
.flat_map(|f| ImageFile::at_path(&f, f.to_str().unwrap_or_default()))
|
||||||
|
.collect();
|
||||||
|
let spritesheet = Spritesheet::build(
|
||||||
|
texture_packer::TexturePackerConfig {
|
||||||
|
max_width: size,
|
||||||
|
max_height: size,
|
||||||
|
allow_rotation: false,
|
||||||
|
force_max_dimensions: true,
|
||||||
|
border_padding: 2,
|
||||||
|
texture_padding: 2,
|
||||||
|
texture_extrusion: 2,
|
||||||
|
trim: false,
|
||||||
|
texture_outlines: false,
|
||||||
|
},
|
||||||
|
&images,
|
||||||
|
&atlas_filename,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if Path::new(&atlas_json_filename).exists() {
|
||||||
|
std::fs::remove_file(&atlas_json_filename).expect("Could not remove the old file");
|
||||||
|
}
|
||||||
|
if Path::new(&atlas_filename).exists() {
|
||||||
|
std::fs::remove_file(&atlas_filename).expect("Could not remove the old file");
|
||||||
|
}
|
||||||
|
match format {
|
||||||
|
SaveImageFormat::Dds => {
|
||||||
|
#[cfg(feature = "dds")]
|
||||||
|
spritesheet.save_as_dds(&atlas_filename);
|
||||||
|
#[cfg(not(feature = "dds"))]
|
||||||
|
panic!("Program is compiled without support for dds. Compile it yourself with feature `dds` enabled.");
|
||||||
|
}
|
||||||
|
f => {
|
||||||
|
spritesheet
|
||||||
|
.image_data
|
||||||
|
.save_with_format(&atlas_filename, f.into())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let json = serde_json::to_string_pretty(&spritesheet.atlas_asset_json)?;
|
||||||
|
let mut file = std::fs::File::create(&atlas_json_filename)?;
|
||||||
|
file.write_all(json.as_bytes())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn create_config(
|
||||||
|
config_path: String,
|
||||||
|
output_path: Option<String>,
|
||||||
|
size: Option<u32>,
|
||||||
|
format: Option<SaveImageFormat>,
|
||||||
|
source_paths: Vec<String>,
|
||||||
|
) -> Result<(), anyhow::Error> {
|
||||||
|
let name = output_path.unwrap_or("tilemap".to_owned());
|
||||||
|
let format = format.unwrap_or_default();
|
||||||
|
let size = size.unwrap_or(512);
|
||||||
|
let config = TilemapGenerationConfig {
|
||||||
|
size,
|
||||||
|
asset_paths: source_paths,
|
||||||
|
output_path: name,
|
||||||
|
format,
|
||||||
|
};
|
||||||
|
|
||||||
|
let json = serde_json::to_string_pretty(&config)?;
|
||||||
|
let mut file = std::fs::File::create(format!("{}.rpack_gen.json", config_path)).unwrap();
|
||||||
|
file.write_all(json.as_bytes())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_tilemap_from_config(config_path: String) -> anyhow::Result<()> {
|
||||||
|
let config_file = std::fs::read_to_string(&config_path)?;
|
||||||
|
let config: TilemapGenerationConfig = serde_json::from_str(&config_file)?;
|
||||||
|
|
||||||
|
let images: Vec<ImageFile> = config
|
||||||
|
.asset_paths
|
||||||
|
.iter()
|
||||||
|
.flat_map(|path| {
|
||||||
|
let pattern = format!("{}/*png", path);
|
||||||
|
glob::glob(&pattern)
|
||||||
|
.unwrap()
|
||||||
|
.flatten()
|
||||||
|
.flat_map(|f| ImageFile::at_path(&f, f.to_str().unwrap_or_default()))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let atlas_filename = format!("{}{}", config.output_path, config.format);
|
||||||
|
let atlas_json_filename = format!("{}.rpack.json", config.output_path);
|
||||||
|
let spritesheet = Spritesheet::build(
|
||||||
|
texture_packer::TexturePackerConfig {
|
||||||
|
max_width: config.size,
|
||||||
|
max_height: config.size,
|
||||||
|
allow_rotation: false,
|
||||||
|
force_max_dimensions: true,
|
||||||
|
border_padding: 2,
|
||||||
|
texture_padding: 2,
|
||||||
|
texture_extrusion: 2,
|
||||||
|
trim: false,
|
||||||
|
texture_outlines: false,
|
||||||
|
},
|
||||||
|
&images,
|
||||||
|
&atlas_filename,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if Path::new(&atlas_json_filename).exists() {
|
||||||
|
std::fs::remove_file(&atlas_json_filename).expect("Could not remove the old file");
|
||||||
|
}
|
||||||
|
if Path::new(&atlas_filename).exists() {
|
||||||
|
std::fs::remove_file(&atlas_filename).expect("Could not remove the old file");
|
||||||
|
}
|
||||||
|
match config.format {
|
||||||
|
SaveImageFormat::Dds => {
|
||||||
|
#[cfg(feature = "dds")]
|
||||||
|
spritesheet.save_as_dds(&atlas_filename);
|
||||||
|
#[cfg(not(feature = "dds"))]
|
||||||
|
panic!("Program is compiled without support for dds. Compile it yourself with feature `dds` enabled.");
|
||||||
|
}
|
||||||
|
f => {
|
||||||
|
spritesheet
|
||||||
|
.image_data
|
||||||
|
.save_with_format(&atlas_filename, f.into())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let json = serde_json::to_string_pretty(&spritesheet.atlas_asset_json)?;
|
||||||
|
let mut file = std::fs::File::create(&atlas_json_filename)?;
|
||||||
|
file.write_all(json.as_bytes())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
use bevy_rpack::{AtlasFrame, SerializableRect};
|
use bevy_rpack::{AtlasFrame, SerializableRect};
|
||||||
use image::DynamicImage;
|
use image::DynamicImage;
|
||||||
|
use thiserror::Error;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::path::Path;
|
use std::{fmt::Display, path::Path};
|
||||||
use texture_packer::{importer::ImageImporter, TexturePacker, TexturePackerConfig};
|
use texture_packer::{importer::ImageImporter, TexturePacker, TexturePackerConfig};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -34,32 +36,68 @@ impl ImageFile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Copy, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(feature = "cli", derive(clap::ValueEnum))]
|
||||||
|
pub enum SaveImageFormat {
|
||||||
|
#[default]
|
||||||
|
Png,
|
||||||
|
Dds,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for SaveImageFormat {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
SaveImageFormat::Png => f.write_str(".png"),
|
||||||
|
SaveImageFormat::Dds => f.write_str(".dds"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SaveImageFormat> for image::ImageFormat {
|
||||||
|
fn from(val: SaveImageFormat) -> Self {
|
||||||
|
match val {
|
||||||
|
SaveImageFormat::Png => image::ImageFormat::Png,
|
||||||
|
SaveImageFormat::Dds => image::ImageFormat::Dds,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Errors that can occur while building a `Spritesheet`.
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum SpritesheetError {
|
||||||
|
#[error("Cannot pack image: {0}")]
|
||||||
|
CannotPackImage(String),
|
||||||
|
#[error("Failed to export tilemap image")]
|
||||||
|
FailedToExportImage,
|
||||||
|
#[error("could not parse asset: {0}")]
|
||||||
|
ParsingError(#[from] serde_json::Error),
|
||||||
|
#[error("Failed to pack image into tilemap, tilemap to small")]
|
||||||
|
FailedToPackImage,
|
||||||
|
}
|
||||||
|
|
||||||
impl Spritesheet {
|
impl Spritesheet {
|
||||||
pub fn build<P>(
|
pub fn build<P>(
|
||||||
config: TexturePackerConfig,
|
config: TexturePackerConfig,
|
||||||
images: &[ImageFile],
|
images: &[ImageFile],
|
||||||
filename: P,
|
filename: P,
|
||||||
) -> Result<Self, String>
|
) -> Result<Self, SpritesheetError>
|
||||||
where
|
where
|
||||||
P: AsRef<str>,
|
P: AsRef<str>,
|
||||||
{
|
{
|
||||||
let mut packer = TexturePacker::new_skyline(config);
|
let mut packer = TexturePacker::new_skyline(config);
|
||||||
for image in images.iter() {
|
for image in images.iter() {
|
||||||
if !packer.can_pack(&image.image) {
|
if !packer.can_pack(&image.image) {
|
||||||
return Err(format!(
|
return Err(SpritesheetError::CannotPackImage(image.id.clone()));
|
||||||
"Consider making atlas bigger. Could not make atlas, failed on: {}",
|
|
||||||
image.id
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
if let Err(err) = packer.pack_own(&image.id, image.image.clone()) {
|
if let Err(_err) = packer.pack_own(&image.id, image.image.clone()) {
|
||||||
return Err(format!(
|
return Err(SpritesheetError::FailedToPackImage);
|
||||||
"Could not make atlas, failed on: {}, {:?}",
|
|
||||||
image.id, err
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let Ok(image_data) = texture_packer::exporter::ImageExporter::export(&packer, None) else {
|
let Ok(image_data) = texture_packer::exporter::ImageExporter::export(&packer, None) else {
|
||||||
return Err("Failed to export image".to_owned());
|
return Err(SpritesheetError::FailedToExportImage);
|
||||||
};
|
};
|
||||||
|
|
||||||
let atlas_asset = bevy_rpack::AtlasAsset {
|
let atlas_asset = bevy_rpack::AtlasAsset {
|
||||||
|
|
@ -81,9 +119,7 @@ impl Spritesheet {
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
let Ok(atlas_asset_json) = serde_json::to_value(&atlas_asset) else {
|
let atlas_asset_json = serde_json::to_value(&atlas_asset)?;
|
||||||
return Err("Failed to deserialize".to_owned());
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Spritesheet {
|
Ok(Spritesheet {
|
||||||
image_data,
|
image_data,
|
||||||
|
|
@ -230,3 +266,11 @@ impl Spritesheet {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct TilemapGenerationConfig {
|
||||||
|
pub asset_paths: Vec<String>,
|
||||||
|
pub output_path: String,
|
||||||
|
pub format: SaveImageFormat,
|
||||||
|
pub size: u32
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,114 +1,18 @@
|
||||||
use clap::{Parser, ValueEnum};
|
use clap::Parser;
|
||||||
use rpack_cli::{ImageFile, Spritesheet};
|
|
||||||
use std::{fmt::Display, io::Write, path::Path};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Copy, ValueEnum)]
|
pub mod commands;
|
||||||
pub enum SaveImageFormat {
|
|
||||||
#[default]
|
|
||||||
Png,
|
|
||||||
Dds,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for SaveImageFormat {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
SaveImageFormat::Png => f.write_str(".png"),
|
|
||||||
SaveImageFormat::Dds => f.write_str(".dds"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<SaveImageFormat> for image::ImageFormat {
|
|
||||||
fn from(val: SaveImageFormat) -> Self {
|
|
||||||
match val {
|
|
||||||
SaveImageFormat::Png => image::ImageFormat::Png,
|
|
||||||
SaveImageFormat::Dds => image::ImageFormat::Dds,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build rpack tilemaps with ease
|
/// Build rpack tilemaps with ease
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = "rpack CLI tool")]
|
||||||
struct Args {
|
struct Args {
|
||||||
/// Name of the tilemap to build, when no value is provided uses 'tilemap'
|
#[command(subcommand)]
|
||||||
#[arg(action)]
|
command: crate::commands::Commands,
|
||||||
name: Option<String>,
|
|
||||||
/// size of the tilemap, default: 512
|
|
||||||
#[arg(long)]
|
|
||||||
size: Option<u32>,
|
|
||||||
/// Image format
|
|
||||||
#[clap(short, long)]
|
|
||||||
format: Option<SaveImageFormat>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> anyhow::Result<()> {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let name = args.name.unwrap_or("tilemap".to_owned());
|
|
||||||
let format = args.format.unwrap_or_default();
|
|
||||||
let atlas_filename = format!("{}{}", name, format);
|
|
||||||
let atlas_json_filename = format!("{}.png", name);
|
|
||||||
let size = args.size.unwrap_or(512);
|
|
||||||
|
|
||||||
let images: Vec<ImageFile> = glob::glob("**/*png")
|
args.command.run()?;
|
||||||
.expect("Failed to find the png files")
|
Ok(())
|
||||||
.flatten()
|
|
||||||
.flat_map(|f| ImageFile::at_path(&f, f.to_str().unwrap_or_default()))
|
|
||||||
.collect();
|
|
||||||
let spritesheet = Spritesheet::build(
|
|
||||||
texture_packer::TexturePackerConfig {
|
|
||||||
max_width: size,
|
|
||||||
max_height: size,
|
|
||||||
allow_rotation: false,
|
|
||||||
force_max_dimensions: true,
|
|
||||||
border_padding: 2,
|
|
||||||
texture_padding: 2,
|
|
||||||
texture_extrusion: 2,
|
|
||||||
trim: false,
|
|
||||||
texture_outlines: false,
|
|
||||||
},
|
|
||||||
&images,
|
|
||||||
&atlas_filename,
|
|
||||||
)
|
|
||||||
.expect("Failed to build spritesheet");
|
|
||||||
|
|
||||||
if Path::new(&atlas_json_filename).exists() {
|
|
||||||
std::fs::remove_file(&atlas_json_filename).expect("Could not remove the old file");
|
|
||||||
}
|
|
||||||
if Path::new(&atlas_filename).exists() {
|
|
||||||
std::fs::remove_file(&atlas_filename).expect("Could not remove the old file");
|
|
||||||
}
|
|
||||||
match format {
|
|
||||||
SaveImageFormat::Dds => {
|
|
||||||
#[cfg(feature = "dds")]
|
|
||||||
spritesheet.save_as_dds(&atlas_filename);
|
|
||||||
#[cfg(not(feature = "dds"))]
|
|
||||||
panic!("Program is compiled without support for dds. Compile it yourself with feature `dds` enabled.");
|
|
||||||
}
|
|
||||||
f => {
|
|
||||||
let write_result = spritesheet
|
|
||||||
.image_data
|
|
||||||
.save_with_format(&atlas_filename, f.into());
|
|
||||||
|
|
||||||
if write_result.is_err() {
|
|
||||||
eprintln!(
|
|
||||||
"Could not make atlas, error: {:?}",
|
|
||||||
write_result.unwrap_err()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
println!("Output texture stored in {}", atlas_json_filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let json = serde_json::to_string_pretty(&spritesheet.atlas_asset_json).unwrap();
|
|
||||||
let mut file = std::fs::File::create(format!("{}.rpack.json", name)).unwrap();
|
|
||||||
let write_result = file.write_all(json.as_bytes());
|
|
||||||
if write_result.is_err() {
|
|
||||||
eprintln!(
|
|
||||||
"Could not make atlas, error: {:?}",
|
|
||||||
write_result.unwrap_err()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
println!("Output data stored in {:?}", file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue