diff --git a/TODO.md b/TODO.md index 0a59acd..7f6a639 100644 --- a/TODO.md +++ b/TODO.md @@ -1,11 +1,8 @@ # todo -* tests * if image is exactly 128×128, *don't* crop * tile reuse * noise reduction (remove lonely pixels) * implement Atkinson and Bayer dithering options -* if "create new bitsy game", add new room as room 0 -* actually create room * stats for added room (number of tiles) * dedupe "palette from custom colours" functionality diff --git a/src/lib.rs b/src/lib.rs index 4d43ac0..b6c3063 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -269,48 +269,57 @@ pub fn add_room() -> String { }, }); - let width = state.image.as_ref().unwrap().width(); - let height = state.image.as_ref().unwrap().height(); + let foreground = &game.palettes + .iter() + .find(|&palette| &palette.id == palette_id.as_ref().unwrap()) + .unwrap().colours[1].clone(); + + let preview = render_preview(&state); + + let width = 128; + let height = 128; let columns = (width as f64 / SD as f64).floor() as u32; let rows = (height as f64 / SD as f64).floor() as u32; let mut tile_ids = Vec::new(); - let mut new_tile_count: u32 = 0; + let initial_tile_count = game.tiles.len(); - for column in 0..columns { - for row in 0..rows { + for row in 0..rows { + for column in 0..columns { let mut pixels = Vec::with_capacity(64); + fn colour_match(a: &image::Rgb, b: &bitsy_parser::Colour) -> u8 { + if a[0] == b.red && a[1] == b.green && a[2] == b.blue { 1 } else { 0 } + }; + for y in (row * SD)..((row + 1) * SD) { for x in (column * SD)..((column + 1) * SD) { - let pixel = state.image.as_ref().unwrap().get_pixel(x, y).to_rgb(); - let total = pixel[0] as u32 + pixel[1] as u32 + pixel[2] as u32; - // is each channel brighter than 128/255 on average? - pixels.push(if total >= 384 {1} else {0}); + let pixel = preview.get_pixel(x, y).to_rgb(); + pixels.push(colour_match(&pixel, foreground)); } } let tile = Tile { // "0" will get overwritten to a new, safe tile ID id: "0".to_string(), - name: tile_name(&state.room_name, &new_tile_count), + name: tile_name(&state.room_name, &(row * column)), wall: None, animation_frames: vec![Image { pixels }], colour_id: None }; - tile_ids.push( - if game.tiles.contains(&tile) { - game.tiles.iter().find(|&t| t == &tile).unwrap().id.clone() - } else { - new_tile_count += 1; - game.add_tile(tile.clone()) - } - ); + let tile_id = if game.tiles.contains(&tile) { + game.tiles.iter().find(|&t| t == &tile).unwrap().id.clone() + } else { + game.add_tile(tile) + }; + + tile_ids.push(tile_id); } } - // todo if player selected "create new game", delete room 0 here + // todo if player selected "create new game", delete room 0 here? + // that would probably break unless the avatar was also placed in the room game.add_room(bitsy_parser::Room { id: "0".to_string(), @@ -325,12 +334,14 @@ pub fn add_room() -> String { game.dedupe_tiles(); + let new_tile_count = game.tiles.len(); + state.game = Some(game.to_owned()); format!( "Added room \"{}\" with {} new tiles", &state.room_name.as_ref().unwrap_or(&"untitled".to_string()), - new_tile_count + new_tile_count - initial_tile_count ) } @@ -376,9 +387,9 @@ mod test { #[test] fn example() { load_default_game(); - load_image(include_str!("test-resources/test.png.base64").to_string()); - add_room(); - - assert_eq!(output(), include_str!("test-resources/expected.bitsy")); + load_image(include_str!("test-resources/test.png.base64").trim().to_string()); + println!("add_room(): {}", add_room()); + // todo what? why are extraneous pixels appearing in the output tiles? + assert_eq!( output(), include_str!("test-resources/expected.bitsy")); } } diff --git a/src/test-resources/expected.bitsy b/src/test-resources/expected.bitsy index 1bbfbd3..6919a0a 100644 --- a/src/test-resources/expected.bitsy +++ b/src/test-resources/expected.bitsy @@ -30,6 +30,25 @@ ROOM 0 NAME example room PAL 0 +ROOM 1 +a,a,1,1,2,2,3,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +PAL 0 + TIL a 11111111 10000001 @@ -41,7 +60,7 @@ TIL a 11111111 NAME block -TIL 2 +TIL 1 00011000 00111000 00011000 @@ -51,7 +70,7 @@ TIL 2 00011000 00111100 -TIL 3 +TIL 2 00111100 01100110 01100110 @@ -61,7 +80,7 @@ TIL 3 01100000 01111110 -TIL 4 +TIL 3 00111100 01100110 01100110 diff --git a/src/test-resources/test.png b/src/test-resources/test.png index 63df3da..0455f0c 100644 Binary files a/src/test-resources/test.png and b/src/test-resources/test.png differ diff --git a/src/test-resources/test.png.base64 b/src/test-resources/test.png.base64 index 4c542ca..acc6769 100644 --- a/src/test-resources/test.png.base64 +++ b/src/test-resources/test.png.base64 @@ -1 +1 @@ -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAAQCAYAAACm53kpAAAAvElEQVR4nO2QQQrDMBAD6/8/upVSBMqClab2IWAP2M1qtgmovcFrgNYa7i96lWdO8nKi7oz6HkcBvWUo3FgKXo7PQpmTvJzy2XNiWgGEM/HM6fmaz54TpwLwiBvhjVnPhDPxzLny5Gpn1FceVcCoJ7/sOKcCKlC4sRS8O87EMyf55Ejy1dU58YgCerm46+ucOArA79/oI/U1ykXy1QntXHlSd9wluHX+52LsAnB2ATjLsgvA2QXgLMvyBXwAjqzoAQg4VfAAAAAASUVORK5CYII= +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABHNCSVQICAgIfAhkiAAAAcJJREFUeJzt19FqgzAAQFEz+v+/nD1t2NLWsQgW7jlP2ogVvUYdc865LRhj/C7/7Gr/29678cfDeNxmdZznbtv2vwu2H39cPtr26H/mnNuc8259ZZzXvs7a0dHJdjE+022/sjKFrzh6jKyO89ppM8AZrgqw7C6AMcbbk3s0vmL1BfLZewDHPmIGcOdfZ5z1GbjymfbqEI7u5nf7EMvfjG3bzJVhH/EI4DoCiBNAnADiBBAngDgBxAkgTgBxAogTQJwA4gQQJ4A4AcQJIE4AcQKIE0CcAOIEECeAOAHECSBOAHECiBNAnADiBBAngDgBxAkgTgBxAogTQJwA4gQQJ4A4AcQJIE4AcQKIE0CcAOIEECeAOAHECSBOAHECiBNAnADiBBAngDgBxAkgTgBxAogTQJwA4gQQJ4A4AcQJIE4AcQKIE0CcAOIEECeAOAHECSBOAHECiBNAnADiBBAngDgBxAkgTgBxAogTQJwA4gQQJ4A4AcQJIE4AcQKIE0CcAOIEECeAOAHECSBOAHECiBNAnADiBBAngDgBxAkgTgBxAogTQJwA4gQQJ4A4AcQJIE4AcQKIE0CcAOIEECeAOAHEfQM+SHkFb+/YEwAAAABJRU5ErkJggg==