auto-gen spritesheets
@ -3,6 +3,7 @@ members = ["./game/game_logic", "./game/desktop_wrapper"]
|
|||||||
exclude = [
|
exclude = [
|
||||||
"./third_party/raylib-rs/raylib",
|
"./third_party/raylib-rs/raylib",
|
||||||
"./third_party/raylib-rs/raylib-sys",
|
"./third_party/raylib-rs/raylib-sys",
|
||||||
|
"./automation/anim_stitcher"
|
||||||
]
|
]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
17
automation/anim_stitcher/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "anim_stitcher"
|
||||||
|
publish = false
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[dependencies]
|
||||||
|
serde = { version = "1.0.126", features = ["derive"] }
|
||||||
|
serde_json = "1.0.64"
|
||||||
|
build-helper = { version = "0.1.1", optional = true }
|
||||||
|
image = { version = "0.24.1", optional = true }
|
||||||
|
regex = { version = "1.5.5", optional = true }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
generator = ["build-helper", "image", "regex"]
|
66
automation/anim_stitcher/src/generator.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use image::{GenericImage, ImageResult};
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
const SPRITE_TYPE_RE: &str = r"^([a-z]+)_";
|
||||||
|
|
||||||
|
fn sprite_name_to_output_dir(sprite_name: &str) -> PathBuf {
|
||||||
|
// Determine the sprite type
|
||||||
|
let sprite_type: String = Regex::new(SPRITE_TYPE_RE)
|
||||||
|
.unwrap()
|
||||||
|
.captures(sprite_name)
|
||||||
|
.unwrap()
|
||||||
|
.get(1)
|
||||||
|
.unwrap()
|
||||||
|
.as_str()
|
||||||
|
.to_string()
|
||||||
|
.into();
|
||||||
|
|
||||||
|
// Build the output directory
|
||||||
|
Path::new("../dist/gen/anm/")
|
||||||
|
.join(sprite_type)
|
||||||
|
.join(sprite_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stitch_sprites(sprite_name: &str, ordered_image_files: Vec<PathBuf>) -> ImageResult<()> {
|
||||||
|
build_helper::warning!(
|
||||||
|
"Generating sprite `{}` from {} images",
|
||||||
|
sprite_name,
|
||||||
|
ordered_image_files.len()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Collect all images into a vec of actual image data
|
||||||
|
let mut images = Vec::new();
|
||||||
|
for image_file in ordered_image_files {
|
||||||
|
let image_data = image::open(image_file.as_path()).unwrap();
|
||||||
|
images.push(image_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the final width and height of the sprite
|
||||||
|
let img_width_out: u32 = images.iter().map(|im| im.width()).sum();
|
||||||
|
let img_height_out: u32 = images.iter().map(|im| im.height()).max().unwrap_or(0);
|
||||||
|
|
||||||
|
// Initialize an image buffer with the appropriate size.
|
||||||
|
let mut imgbuf = image::ImageBuffer::new(img_width_out, img_height_out);
|
||||||
|
let mut accumulated_width = 0;
|
||||||
|
|
||||||
|
// Copy each input image at the correct location in the output image.
|
||||||
|
for img in images {
|
||||||
|
imgbuf.copy_from(&img, accumulated_width, 0).unwrap();
|
||||||
|
accumulated_width += img.width();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the output directory
|
||||||
|
let output_dir = sprite_name_to_output_dir(sprite_name);
|
||||||
|
|
||||||
|
// Create the output directory if it doesn't exist
|
||||||
|
if !output_dir.exists() {
|
||||||
|
std::fs::create_dir_all(output_dir.as_path()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the output image to disk.
|
||||||
|
imgbuf.save(output_dir.join(format!("{}.png", sprite_name)))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
3
automation/anim_stitcher/src/lib.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
#[cfg(feature = "generator")]
|
||||||
|
pub mod generator;
|
9
game/auto_stitch/README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# The Auto-Stitch directory
|
||||||
|
|
||||||
|
This is a bit of a *magic* directory. Anything put in here will automatically be turned into a spritesheet at compile time.
|
||||||
|
|
||||||
|
## File organization
|
||||||
|
|
||||||
|
In this directory, framesets are expected to be stored in subdirectories. The names of these are important as they will translate into the names of the spritesheets.
|
||||||
|
|
||||||
|
For example, if you put a set of frames in `auto_stitch/chr_testFox`, you will get a spritesheet generated to `dist/gen/anm/chr/chr_testFox.png`.
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 132 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 107 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 107 KiB |
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 107 KiB |
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 109 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 116 KiB |
1
game/dist/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/gen/*
|
@ -3,20 +3,26 @@ name = "game_logic"
|
|||||||
publish = false
|
publish = false
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
[dependencies]
|
[dependencies]
|
||||||
raylib = { version = "3.7", path = "../../third_party/raylib-rs/raylib" }
|
raylib = { version = "3.7", path = "../../third_party/raylib-rs/raylib" }
|
||||||
sad_machine = { version = "1.0", path = "../../third_party/sm" }
|
sad_machine = { version = "1.0", path = "../../third_party/sm" }
|
||||||
tokio = { version = "1.17.0", featurs = ["fs"] }
|
tokio = { version = "1.17.0", features = ["fs"] }
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
profiling = "1.0.5"
|
profiling = "1.0.5"
|
||||||
serde = { version = "1.0.136", features = ["derive"] }
|
serde = { version = "1.0.136", features = ["derive"] }
|
||||||
serde_json = "1.0.79"
|
serde_json = "1.0.79"
|
||||||
directories = "4.0.1"
|
directories = "4.0.1"
|
||||||
chrono = { verison = "0.4.19", features = ["serde"] }
|
chrono = { version = "0.4.19", features = ["serde"] }
|
||||||
discord-sdk = "0.3.0"
|
discord-sdk = "0.3.0"
|
||||||
rust-embed = { version = "6.2.0", features = ["compression"] }
|
rust-embed = { version = "6.2.0", features = ["compression"] }
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.30"
|
||||||
# nalgebra = { version = "0.30.1", features = ["serde"] }
|
# nalgebra = { version = "0.30.1", features = ["serde"] }
|
||||||
approx = "0.5.1"
|
approx = "0.5.1"
|
||||||
|
|
||||||
|
[build-dependencies.anim_stitcher]
|
||||||
|
version = "*"
|
||||||
|
features = ["generator"]
|
||||||
|
path = "../../automation/anim_stitcher"
|
||||||
|
26
game/game_logic/build.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//! This script contains code that generates more code.
|
||||||
|
//!
|
||||||
|
//! The idea being that we can have assets auto-pack and optimize themselves at build time.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// We want to re-build if the assets change
|
||||||
|
println!("cargo:rerun-if-changed=../auto_stitch");
|
||||||
|
|
||||||
|
// Search for all direct children of the auto_stitch directory
|
||||||
|
for entry in std::fs::read_dir("../auto_stitch").unwrap() {
|
||||||
|
let entry = entry.unwrap();
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
// Get all children of the current entry
|
||||||
|
if let Ok(children) = std::fs::read_dir(&path) {
|
||||||
|
let children_paths = children.map(|e| e.unwrap().path()).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Process into a sprite
|
||||||
|
anim_stitcher::generator::stitch_sprites(
|
||||||
|
path.file_name().unwrap().to_str().unwrap(),
|
||||||
|
children_paths,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|