Modify data structures to include palette data per tile

stinkhead7ds
Ashley N. 2023-09-13 21:10:36 -04:00
parent f7b9216680
commit ff08ee4e46
3 changed files with 57 additions and 22 deletions

View File

@ -67,7 +67,7 @@ pub fn run_command() -> Result<(), Box<dyn Error>> {
} }
Tools::Level { input_file, output_directory, console, tile_size } => { Tools::Level { input_file, output_directory, console, tile_size } => {
let tiled_file = get_tiled_tilemap( &input_file )?; let tiled_file = get_tiled_tilemap( &input_file )?;
print_info( &format!( "{:#?}", tiled_file ) ); //print_info( &format!( "{:#?}", tiled_file ) );
print_good( "file opened without errors" ); print_good( "file opened without errors" );
print_error( "unimplemented" ); print_error( "unimplemented" );
} }

View File

@ -10,14 +10,13 @@ pub struct TiledTilemap {
pub layers: Vec<Layer>, pub layers: Vec<Layer>,
ecs: Vec<ecs::Entity>, ecs: Vec<ecs::Entity>,
pub width: usize, pub width: usize,
pub height: usize, pub height: usize
pub tile_width: usize,
pub tile_height: usize
} }
#[derive(Debug)] #[derive(Debug)]
pub struct TiledTileset { pub struct TiledTileset {
pub image: DynamicImage pub image: DynamicImage,
pub palettes: Vec<Option<u8>>
} }
#[derive(Debug)] #[derive(Debug)]
@ -103,6 +102,42 @@ fn get_layer( layer: Node, map_width: usize, map_height: usize ) -> Result<Optio
} }
} }
fn get_tiles( tileset: Node ) -> Result<TiledTileset, Box<dyn Error>> {
// Get the image for the tileset
let image = tileset.descendants().find( | node | node.tag_name() == "image".into() ).ok_or( "invalid file: no image object" )?;
let image = image::open( image.attribute( "source" ).ok_or( "invalid file: no source attribute on image" )? )?;
// Image must be a multiple of 8 (--system md)
if image.width() % 8 != 0 { return Err( "invalid file: tileset width not multiple of 8" )? }
if image.height() % 8 != 0 { return Err( "invalid file: tileset height not multiple of 8" )? }
let tile_count: usize = tileset.attribute( "tilecount" ).ok_or( "invalid file: no tilecount attribute on tileset" )?.parse()?;
let mut palettes: Vec<Option<u8>> = vec![ None; tile_count ];
let defined_tiles = tileset.descendants().filter( | node | node.tag_name() == "tile".into() );
for defined_tile in defined_tiles {
let tile_id: usize = defined_tile.attribute( "id" ).ok_or( "invalid file: id attribute not defined on a tile" )?.parse()?;
let properties = defined_tile.descendants().find( | node | node.tag_name() == "properties".into() ).ok_or( "invalid file: no properties descendant in tileset" )?;
let property = properties.descendants().find( | node | node.tag_name() == "property".into() && node.attribute( "reskit-palette" ).is_some() );
if let Some( property ) = property {
let property_type = property.attribute( "type" ).unwrap_or( "string" );
if property_type == "int" {
let palette_value: u8 = property.attribute( "value" ).ok_or( "invalid file: reskit-palette property has no value" )?.parse()?;
// --system md
if palette_value > 3 {
print_warning( &format!( "reskit-palette property on tile {} is not valid palette (0 to 3) - leaving palette unset, this is probably not what you want...", tile_id ) );
} else {
palettes[ tile_id ] = Some( palette_value );
}
} else {
print_warning( &format!( "reskit-palette property on tile {} is not int type - leaving palette unset, this is probably not what you want...", tile_id ) )
}
}
}
Ok( TiledTileset { image, palettes } )
}
pub fn get_tiled_tilemap( path: &str ) -> Result<TiledTilemap, Box<dyn Error>> { pub fn get_tiled_tilemap( path: &str ) -> Result<TiledTilemap, Box<dyn Error>> {
let file = read_to_string( path )?; let file = read_to_string( path )?;
let document = roxmltree::Document::parse( &file )?; let document = roxmltree::Document::parse( &file )?;
@ -135,6 +170,14 @@ pub fn get_tiled_tilemap( path: &str ) -> Result<TiledTilemap, Box<dyn Error>> {
map.attribute( "tileheight" ).ok_or( "invalid file: no tileheight attribute" )?.parse()? map.attribute( "tileheight" ).ok_or( "invalid file: no tileheight attribute" )?.parse()?
); );
// --system md is 8x8
if tile_width != 8 {
return Err( "invalid file: tile width is not 8 for --system md" )?
}
if tile_height != 8 {
return Err( "invalid file: tile height is not 8 for --system md" )?
}
// Build tileset (current version assumes one tileset per level) // Build tileset (current version assumes one tileset per level)
let tileset = map.descendants().find( | node | node.tag_name() == "tileset".into() ).ok_or( "invalid file: no tileset" )?; let tileset = map.descendants().find( | node | node.tag_name() == "tileset".into() ).ok_or( "invalid file: no tileset" )?;
let tileset_source_path = tileset.attribute( "source" ).ok_or( "invalid file: no tileset source" )?; let tileset_source_path = tileset.attribute( "source" ).ok_or( "invalid file: no tileset source" )?;
@ -152,13 +195,7 @@ pub fn get_tiled_tilemap( path: &str ) -> Result<TiledTilemap, Box<dyn Error>> {
return Err( "invalid file: referenced tilemap doesn't have same per-tile width and height of parent tilemap" )? return Err( "invalid file: referenced tilemap doesn't have same per-tile width and height of parent tilemap" )?
} }
// Get the image for the tileset let tileset = get_tiles( tileset )?;
let image = tileset.descendants().find( | node | node.tag_name() == "image".into() ).ok_or( "invalid file: no image object" )?;
let image = image::open( image.attribute( "source" ).ok_or( "invalid file: no source attribute on image" )? )?;
// Image must be a multiple of 8 (md system)
if image.width() % 8 != 0 { return Err( "invalid file: tileset width not multiple of 8" )? }
if image.height() % 8 != 0 { return Err( "invalid file: tileset height not multiple of 8" )? }
// Get the layers // Get the layers
let layers: Vec<Layer> = map.descendants() let layers: Vec<Layer> = map.descendants()
@ -184,13 +221,11 @@ pub fn get_tiled_tilemap( path: &str ) -> Result<TiledTilemap, Box<dyn Error>> {
Ok( Ok(
TiledTilemap { TiledTilemap {
tileset: TiledTileset { image }, tileset,
layers, layers,
ecs, ecs,
width, width,
height, height
tile_width,
tile_height
} }
) )
} else { } else {

View File

@ -10,13 +10,13 @@ pub fn get_tiles( tilemap: &TiledTilemap ) -> Result<Vec<u8>, Box<dyn Error>> {
let mut palette: [u16; 16] = [ 0; 16 ]; let mut palette: [u16; 16] = [ 0; 16 ];
let mut all_tiles: Vec<u8> = Vec::new(); let mut all_tiles: Vec<u8> = Vec::new();
for tile_y in 0..tilemap.tile_height { for tile_y in 0..tilemap.height {
for tile_x in 0..tilemap.tile_width { for tile_x in 0..tilemap.width {
let tile = tilemap.tileset.image.clone().crop( let tile = tilemap.tileset.image.clone().crop(
tile_x as u32, tile_x as u32,
tile_y as u32, tile_y as u32,
tilemap.tile_width as u32, 8, // --system md
tilemap.tile_height as u32 8 // --system md
); );
let tile_bin = image_to_tiles( let tile_bin = image_to_tiles(
@ -52,8 +52,8 @@ pub fn get_tilemap( tilemap: &TiledTilemap ) -> Result<Vec<u8>, Box<dyn Error>>
let layer_b: Option<&Layer> = tilemap.layers.iter().find( | layer | matches!( layer, Layer::Tile { system_plane: SystemPlane::MdPlaneB, tiles: _ } ) ); 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 layer_a: Option<&Layer> = tilemap.layers.iter().find( | layer | matches!( layer, Layer::Tile { system_plane: SystemPlane::MdPlaneA, tiles: _ } ) );
let md_height_per_tile = tilemap.tile_height / 8; let md_height_per_tile = 1; // --system md
let md_width_per_tile = tilemap.tile_width / 8; let md_width_per_tile = 1; // --system md
// Each entry in a `--system md` tilemap is 16 bits // Each entry in a `--system md` tilemap is 16 bits
let mut nametable: Vec<u16> = vec![ 0; ( tilemap.width * md_width_per_tile ) * ( tilemap.height * md_height_per_tile ) ]; let mut nametable: Vec<u16> = vec![ 0; ( tilemap.width * md_width_per_tile ) * ( tilemap.height * md_height_per_tile ) ];