diff --git a/src/reskit/level/system.rs b/src/reskit/level/system.rs index 2023dbc..c1c1ca0 100644 --- a/src/reskit/level/system.rs +++ b/src/reskit/level/system.rs @@ -1,27 +1,44 @@ use std::{error::Error, convert::TryInto}; +use image::GenericImageView; use crate::reskit::tileset::image_to_tiles; use super::converter::{TiledTilemap, Layer, SystemPlane}; /** - * Output the .bin file (using `tileset` tool to build it) containing each of the tiles - * in the Tiled Editor tileset. + * Output the .bin and .pal file (using `tileset` tool to build it) containing each of the tiles + * and palettes in the Tiled Editor tileset. */ -pub fn get_tiles( tilemap: &TiledTilemap ) -> Result, Box> { - let mut palette: [u16; 16] = [ 0; 16 ]; +pub fn get_tiles( tilemap: &TiledTilemap ) -> Result<(Vec, Vec), Box> { + let mut system_pals: [[u16; 16]; 4] = [ + [ 0; 16 ], + [ 0; 16 ], + [ 0; 16 ], + [ 0; 16 ] + ]; let mut all_tiles: Vec = Vec::new(); - for tile_y in 0..tilemap.height { - for tile_x in 0..tilemap.width { - let tile = tilemap.tileset.image.clone().crop( - tile_x as u32, - tile_y as u32, - 8, // --system md - 8 // --system md - ); + let tiles_height = tilemap.tileset.image.height() / 8; // --system md + let tiles_width = tilemap.tileset.image.width() / 8; // --system md + + for tile_y in 0..tiles_height { + for tile_x in 0..tiles_width { + let tile = tilemap.tileset.image.clone().crop( tile_x * 8, tile_y * 8, 8, 8 ); + + // Fake palette (see below) + let mut fake: [u16; 16] = [ 0; 16 ]; let tile_bin = image_to_tiles( &tile, - &mut palette, + { + // Determine if palette is used here or it is a dummy palette + let selected_pal = tilemap.tileset.palettes[ ( ( tile_y * tiles_width ) + tile_x ) as usize ]; + if let Some( selected_pal ) = selected_pal { + &mut system_pals[ selected_pal as usize ] + } else { + // Fake-a-palette + // You will get an error in get_tilemap if you try to use this palette-less tile + &mut fake + } + }, "tile" ); @@ -29,19 +46,18 @@ pub fn get_tiles( tilemap: &TiledTilemap ) -> Result, Box> { } } - // Define result and write palette to top of result - let mut result: Vec = Vec::new(); - for i in 0..palette.len() { - let bytes = palette[ i ].to_be_bytes(); - for i in 0..2 { - result.push( bytes[ i ] ); - } - } + // Define result and write palettes + let mut palettes: Vec = Vec::new(); + for pal in 0..system_pals.len() { + for i in 0..system_pals[ pal ].len() { + let bytes = system_pals[ pal ][ i ].to_be_bytes(); + for i in 0..2 { + palettes.push( bytes[ i ] ); + } + } + } - // Extend all tiles onto result - result.extend( all_tiles ); - - Ok( result ) + Ok( ( all_tiles, palettes ) ) } /** @@ -52,11 +68,8 @@ pub fn get_tilemap( tilemap: &TiledTilemap ) -> Result, Box> let layer_b: Option<&Layer> = tilemap.layers.iter().find( | layer | matches!( layer, Layer::Tile { system_plane: SystemPlane::MdPlaneB, tiles: _ } ) ); let layer_a: Option<&Layer> = tilemap.layers.iter().find( | layer | matches!( layer, Layer::Tile { system_plane: SystemPlane::MdPlaneA, tiles: _ } ) ); - let md_height_per_tile = 1; // --system md - let md_width_per_tile = 1; // --system md - // Each entry in a `--system md` tilemap is 16 bits - let mut nametable: Vec = vec![ 0; ( tilemap.width * md_width_per_tile ) * ( tilemap.height * md_height_per_tile ) ]; + let mut nametable: Vec = vec![ 0; tilemap.width * tilemap.height ]; if let Some( layer_b ) = layer_b { let layer_b = match layer_b { @@ -69,18 +82,15 @@ pub fn get_tilemap( tilemap: &TiledTilemap ) -> Result, Box> let target_tile: u32 = *layer_b.get( ( y * tilemap.width ) + x ).ok_or( "internal error: invalid data in tilemap" )?; let target_tile: u16 = target_tile.try_into()?; if target_tile > 0 { - let wide_tile_size = md_height_per_tile as u16 * md_width_per_tile as u16; - let source_tile = ( target_tile - 1 ) * wide_tile_size; - let x = x * md_width_per_tile; - let y = y * md_height_per_tile; + let source_tile = target_tile - 1; // From the starting point of x, y "stamp" the target tile's indices - let mut revolving_counter = 0; - for y_stamp in y..( y + md_height_per_tile ) { - for x_stamp in x..( x + md_width_per_tile ) { - nametable[ ( y_stamp * ( tilemap.width * md_width_per_tile ) ) + x_stamp ] = source_tile + revolving_counter; - revolving_counter = ( revolving_counter + 1 ) % wide_tile_size; - } + let nametable_entry = source_tile; + let selected_pal = tilemap.tileset.palettes[ source_tile as usize ]; + if let Some( selected_pal ) = selected_pal { + nametable[ ( y * tilemap.width ) + x ] = ( ( selected_pal as u16 ) << 13 ) | nametable_entry; + } else { + return Err( format!( "invalid setting: tile {} in tileset has no defined palette", source_tile ) )? } } } @@ -100,18 +110,15 @@ pub fn get_tilemap( tilemap: &TiledTilemap ) -> Result, Box> let target_tile: u32 = *layer_a.get( ( y * tilemap.width ) + x ).ok_or( "internal error: invalid data in tilemap" )?; let target_tile: u16 = target_tile.try_into()?; if target_tile > 0 { - let wide_tile_size = md_height_per_tile as u16 * md_width_per_tile as u16; - let source_tile = ( target_tile - 1 ) * wide_tile_size; - let x = x * md_width_per_tile; - let y = y * md_height_per_tile; + let source_tile = target_tile - 1; // From the starting point of x, y "stamp" the target tile's indices - let mut revolving_counter = 0; - for y_stamp in y..( y + md_height_per_tile ) { - for x_stamp in x..( x + md_width_per_tile ) { - nametable[ ( y_stamp * ( tilemap.width * md_width_per_tile ) ) + x_stamp ] = source_tile + revolving_counter; - revolving_counter = ( revolving_counter + 1 ) % wide_tile_size; - } + let nametable_entry = source_tile; + let selected_pal = tilemap.tileset.palettes[ source_tile as usize ]; + if let Some( selected_pal ) = selected_pal { + nametable[ ( y * tilemap.width ) + x ] = ( ( selected_pal as u16 ) << 13 ) | nametable_entry; + } else { + return Err( format!( "invalid setting: tile {} in tileset has no defined palette", source_tile ) )? } } }