diff --git a/Cargo.lock b/Cargo.lock index f473f81..f20ecda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "gd-icon-renderer" -version = "1.2.0" +version = "2.0.0" dependencies = [ "image", "imageproc", diff --git a/Cargo.toml b/Cargo.toml index d9e8b7f..e3b201b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "gd-icon-renderer" description = "A tool to render Geometry Dash icons." -version = "1.2.0" +version = "2.0.0" edition = "2021" license-file = "LICENSE" repository = "https://git.reidlab.online/reidlab/gd-icon-renderer" diff --git a/readme.md b/readme.md index 1828bd3..424c99b 100644 --- a/readme.md +++ b/readme.md @@ -28,7 +28,7 @@ Provide your `GJ_GameSheet02-uhd`, `GJ_GameSheetGlow-uhd`, `Robot_AnimDesc2`, an 3. Render the icon out: ```rs - let icon_img = gd_icon_renderer::renderer::render_icon("ship", 44, [0.0, 0.0, 0.0], [255.0/255.0, 125.0/255.0, 125.0/255.0], true, game_sheet_02, game_sheet_glow, robot_sheet, spider_sheet); + let icon_img = gd_icon_renderer::renderer::render_icon("ship", 44, [0.0, 0.0, 0.0], [255.0/255.0, 125.0/255.0, 125.0/255.0], true, game_sheet_02, game_sheet_glow, robot_sheet, spider_sheet).expect("failed to render image"); ``` You'll now be given a [`DynamicImage`](https://docs.rs/image/latest/image/enum.DynamicImage.html) @@ -41,6 +41,6 @@ Provide your `GJ_GameSheet02-uhd`, `GJ_GameSheetGlow-uhd`, `Robot_AnimDesc2`, an ## Todo -- Maybe make render_icon a `Result` +- Improve gamemode selection - Add examples to the repo. - I think theres some weird shifting and offsets going on, please investigate 🥺. Really big on `spider_16` for some reason?? Related issue on the inspired project [here](https://github.com/oatmealine/gd-icon-renderer/issues/2). \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 4fc25b8..96c2358 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,7 +29,7 @@ mod tests { let spider_sheet = load_animations("assets/Spider_AnimDesc2.plist"); let start = Instant::now(); - let rendered_icon = render_icon("spider", 16, [0.0, 0.0, 0.0], [255.0/255.0, 125.0/255.0, 125.0/255.0], true, game_sheet_02, game_sheet_glow, robot_sheet, spider_sheet); + let rendered_icon = render_icon("ship", 44, [0.0, 0.0, 0.0], [255.0/255.0, 125.0/255.0, 125.0/255.0], true, game_sheet_02, game_sheet_glow, robot_sheet, spider_sheet).expect("failed to render image"); let end = start.elapsed(); println!("time taken to render: {:?}", end); diff --git a/src/renderer.rs b/src/renderer.rs index 2127d15..1a28cbc 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -75,7 +75,7 @@ fn transform(image: &DynamicImage, color: Option<[f32; 3]>, scale: Option<(f32, } /// Mainly for internal use; given an array of images, their sizes and colors, tints and composits them into a single image -pub fn render_layered(images: Vec, positions: Vec>, colors: Vec>, scales: Vec>, rotations: Vec>) -> DynamicImage { +pub fn render_layered(images: Vec, positions: Vec>, colors: Vec>, scales: Vec>, rotations: Vec>) -> Result { let transformed: Vec = images.iter().enumerate().map(|(i, img)| { transform(img, colors[i], scales[i], rotations[i]) }).collect(); @@ -103,7 +103,7 @@ pub fn render_layered(images: Vec, positions: Vec, positions: Vec bool { @@ -149,7 +149,7 @@ fn crop_whitespace(img: DynamicImage) -> DynamicImage { } /// Renders out a non-robot/spider icon. You may be looking for `render_icon`. -pub fn render_normal(basename: String, col1: [f32; 3], col2: [f32; 3], glow: bool, game_sheet_02: LoadedSpritesheet, game_sheet_glow: LoadedSpritesheet) -> DynamicImage { +pub fn render_normal(basename: String, col1: [f32; 3], col2: [f32; 3], glow: bool, game_sheet_02: LoadedSpritesheet, game_sheet_glow: LoadedSpritesheet) -> Result { let glow_col = if is_black(col2) { if is_black(col1) { [1.0, 1.0, 1.0] } else { col1 } } else { col2 }; let layers = vec![ @@ -185,9 +185,9 @@ pub fn render_normal(basename: String, col1: [f32; 3], col2: [f32; 3], glow: boo .collect(), vec![None, None, None, None, None], vec![None, None, None, None, None] - ); + )?; - return crop_whitespace(layered_images); + return Ok(crop_whitespace(layered_images)); } fn flip(scale: (f32, f32), flipped: (bool, bool)) -> (f32, f32) { @@ -195,17 +195,13 @@ fn flip(scale: (f32, f32), flipped: (bool, bool)) -> (f32, f32) { } /// Renders out a robot/spider icon. You may be looking for `render_icon`. -pub fn render_zany(basename: String, col1: [f32; 3], col2: [f32; 3], glow: bool, game_sheet_02: LoadedSpritesheet, _game_sheet_glow: LoadedSpritesheet, animations: Animations) -> DynamicImage { +pub fn render_zany(basename: String, col1: [f32; 3], col2: [f32; 3], glow: bool, game_sheet_02: LoadedSpritesheet, _game_sheet_glow: LoadedSpritesheet, animations: Animations) -> Result { let glow_col = if is_black(col2) { if is_black(col1) { [1.0, 1.0, 1.0] } else { col1 } } else { col2 }; let glow = glow || (is_black(col1) && is_black(col2)); let mut anim = animations.get("Robot_idle_001.png").unwrap_or_else(|| animations.get("Spider_idle_001.png").expect("no animations found")).clone(); anim.sort_by_key(|spr| spr.z); - // TODO: this is a bit of a mess - // TODO: this is also very slow, but i dont think it can be helped - // TODO: im not good at memory management so srry - let mut layers: Vec<(Option<(DynamicImage, Sprite)>, (f32, f32), (f32, f32), f64, bool, Option<[f32; 3]>)> = Vec::new(); for a in anim { @@ -254,20 +250,20 @@ pub fn render_zany(basename: String, col1: [f32; 3], col2: [f32; 3], glow: bool, layers_r.iter().map(|t| t.5).collect(), layers_r.iter().map(|t| Some(t.2)).collect(), layers_r.iter().map(|t| Some(t.3 as f32)).collect() - ); + )?; - return crop_whitespace(layered_images); + return Ok(crop_whitespace(layered_images)); } /// The main entrypoint for icon rendering; this should be all you need to render out an icon. /// /// `gamemode` must be one of `cube`, `ship`, `ball`, `ufo`, `wave`, `robot`, or `spider` -pub fn render_icon(gamemode_str: &str, icon: i32, col1: [f32; 3], col2: [f32; 3], glow: bool, game_sheet_02: LoadedSpritesheet, game_sheet_glow: LoadedSpritesheet, robot_animations: Animations, spider_animations: Animations) -> DynamicImage { - let gamemode = crate::constants::GAMEMODES.get(gamemode_str).expect("invalid gamemode"); +pub fn render_icon(gamemode_str: &str, icon: i32, col1: [f32; 3], col2: [f32; 3], glow: bool, game_sheet_02: LoadedSpritesheet, game_sheet_glow: LoadedSpritesheet, robot_animations: Animations, spider_animations: Animations) -> Result { + let gamemode = crate::constants::GAMEMODES.get(gamemode_str).ok_or("Invalid gamemode")?; if gamemode.zany { - return render_zany(format!("{}{:02}", gamemode.prefix, icon), col1, col2, glow, game_sheet_02, game_sheet_glow, if gamemode_str == "robot" { robot_animations } else { spider_animations }) + return Ok(render_zany(format!("{}{:02}", gamemode.prefix, icon), col1, col2, glow, game_sheet_02, game_sheet_glow, if gamemode_str == "robot" { robot_animations } else { spider_animations }))? } else { - return render_normal(format!("{}{:02}", gamemode.prefix, icon), col1, col2, glow, game_sheet_02, game_sheet_glow) + return Ok(render_normal(format!("{}{:02}", gamemode.prefix, icon), col1, col2, glow, game_sheet_02, game_sheet_glow))? } } \ No newline at end of file