From b94cd6e41c5fee97b2daf26d70ca01b740bd70a7 Mon Sep 17 00:00:00 2001 From: Tad Hardesty Date: Sun, 20 Jan 2019 00:24:59 -0800 Subject: [PATCH] Add example for detecting duplicate icon states --- src/dreammaker/dmi.rs | 10 ++- src/tools/dmi.rs | 14 +++- src/tools/examples/duplicate_icon_states.rs | 91 +++++++++++++++++++++ 3 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 src/tools/examples/duplicate_icon_states.rs diff --git a/src/dreammaker/dmi.rs b/src/dreammaker/dmi.rs index 5f679c67..00e46249 100644 --- a/src/dreammaker/dmi.rs +++ b/src/dreammaker/dmi.rs @@ -36,14 +36,14 @@ pub struct State { pub frames: Frames, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Dirs { One, Four, Eight, } -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum Frames { /// Without an explicit setting, only one frame One, @@ -71,6 +71,12 @@ impl Metadata { } } +impl State { + pub fn num_sprites(&self) -> usize { + self.dirs.len() * self.frames.len() + } +} + impl Dirs { pub fn len(self) -> usize { match self { diff --git a/src/tools/dmi.rs b/src/tools/dmi.rs index af7775e0..0b70df79 100644 --- a/src/tools/dmi.rs +++ b/src/tools/dmi.rs @@ -67,8 +67,11 @@ impl IconFile { None if icon_state == "" => 0, None => return None, }; - let state = &self.metadata.states[state_index]; + let index = self.index_of_state(&self.metadata.states[state_index], dir, 0); + Some(self.rect_of_index(index)) + } + pub fn index_of_state(&self, state: &State, dir: i32, frame: u32) -> u32 { let dir_idx = match (state.dirs, dir) { (Dirs::One, _) => 0, (Dirs::Eight, NORTHWEST) => 7, @@ -81,15 +84,18 @@ impl IconFile { (_, _) => 0, }; - let icon_index = state.offset as u32 + dir_idx; + state.offset as u32 + dir_idx + frame * state.dirs.len() as u32 + } + + pub fn rect_of_index(&self, icon_index: u32) -> Rect { let icon_count = self.image.width / self.metadata.width; let (icon_x, icon_y) = (icon_index % icon_count, icon_index / icon_count); - Some(( + ( icon_x * self.metadata.width, icon_y * self.metadata.height, self.metadata.width, self.metadata.height, - )) + ) } } diff --git a/src/tools/examples/duplicate_icon_states.rs b/src/tools/examples/duplicate_icon_states.rs new file mode 100644 index 00000000..82d62f61 --- /dev/null +++ b/src/tools/examples/duplicate_icon_states.rs @@ -0,0 +1,91 @@ +extern crate dreammaker as dm; +extern crate dmm_tools; +extern crate walkdir; +extern crate ndarray; + +use std::path::Path; +use std::collections::HashMap; +use walkdir::{DirEntry, WalkDir}; +use dmm_tools::dmi::*; +use ndarray::s; + +fn is_visible(entry: &DirEntry) -> bool { + entry + .path() + .file_name() + .unwrap_or("".as_ref()) + .to_str() + .map(|s| !s.starts_with(".")) + .unwrap_or(true) +} + +fn files_with_extension(ext: &str, mut f: F) { + let dir = match std::env::var_os("TEST_DME") { + Some(dme) => Path::new(&dme).parent().unwrap().to_owned(), + None => { + println!("Set TEST_DME to check .{} files", ext); + return; + } + }; + for entry in WalkDir::new(dir).into_iter().filter_entry(is_visible) { + let entry = entry.unwrap(); + if entry.file_type().is_file() && entry.path().extension() == Some(ext.as_ref()) { + let path = entry.path(); + f(path); + } + } +} + +fn all_same(icon_file: &IconFile, states: &[&State]) -> bool { + let (first, rest) = states.split_first().unwrap(); + let first_start_index = icon_file.index_of_state(first, 0, 0); + for state in rest { + if state.dirs != first.dirs || state.frames != first.frames { + return false; + } + let start_index = icon_file.index_of_state(state, 0, 0); + for i in 0..state.num_sprites() as u32 { + let rect1 = icon_file.rect_of_index(first_start_index + i); + let rect2 = icon_file.rect_of_index(start_index + i); + let slice1 = icon_file.image.data.slice(s![ + rect1.1 as isize..(rect1.1 + rect1.3) as isize, + rect1.0 as isize..(rect1.0 + rect1.2) as isize, + .. + ]); + let slice2 = icon_file.image.data.slice(s![ + rect2.1 as isize..(rect2.1 + rect2.3) as isize, + rect2.0 as isize..(rect2.0 + rect2.2) as isize, + .. + ]); + if slice1 != slice2 { + return false; + } + } + } + true +} + +pub fn main() { + files_with_extension("dmi", |path| { + let icon_file = IconFile::from_file(path).unwrap(); + let mut counts = HashMap::<_, Vec<_>>::new(); + for state in icon_file.metadata.states.iter() { + let mut name = format!("{:?}", state.name); + if state.movement { + name.push_str(" (movement)"); + } + counts.entry(name).or_default().push(state); + } + let mut name = false; + for (k, v) in counts { + if v.len() > 1 { + if !name { + println!("{}", path.display()); + name = true; + } + let star = if all_same(&icon_file, &v) { "*" } else { " " }; + println!(" {} {}x {}", star, v.len(), k); + } + } + }); +}