From e7fd734e0cb60a535c896c0b8d12b6d6672e4355 Mon Sep 17 00:00:00 2001 From: jaby Date: Sun, 22 Dec 2024 20:25:43 +0100 Subject: [PATCH] Shuffle around more functions --- src/Tools/psxfileconv/src/images/args.rs | 22 +-- src/Tools/psxfileconv/src/images/mod.rs | 145 ++++++++++++++++- .../psxfileconv/src/images/reduced_tim/mod.rs | 148 +----------------- .../src/images/reduced_tim/types.rs | 38 +++++ src/Tools/psxfileconv/src/images/types.rs | 40 +---- 5 files changed, 196 insertions(+), 197 deletions(-) create mode 100644 src/Tools/psxfileconv/src/images/reduced_tim/types.rs diff --git a/src/Tools/psxfileconv/src/images/args.rs b/src/Tools/psxfileconv/src/images/args.rs index 07428dac..0891885d 100644 --- a/src/Tools/psxfileconv/src/images/args.rs +++ b/src/Tools/psxfileconv/src/images/args.rs @@ -8,11 +8,11 @@ pub struct Arguments { #[clap(value_enum, value_parser, default_value_t=ClutAlignment::None)] pub clut_align: ClutAlignment, - #[clap(long=SemiTransparent::NAME, default_value_t=false)] - pub semi_transparent: SemiTransparent::Type, + #[clap(long="semi-trans", default_value_t=false)] + pub semi_transparent: bool, - #[clap(long=TransparentPalette::NAME, default_value_t=false)] - pub transparent_palette: TransparentPalette::Type + #[clap(long="color-trans", default_value_t=false)] + pub transparent_palette: bool } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] @@ -27,16 +27,4 @@ pub enum ClutAlignment { None, Linear, Block -} - -#[allow(non_snake_case)] -pub mod SemiTransparent { - pub type Type = bool; - pub const NAME:&'static str = "semi-trans"; -} - -#[allow(non_snake_case)] -pub mod TransparentPalette { - pub type Type = bool; - pub const NAME:&'static str = ""; -} +} \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/images/mod.rs b/src/Tools/psxfileconv/src/images/mod.rs index 57d61d18..e9b0aadf 100644 --- a/src/Tools/psxfileconv/src/images/mod.rs +++ b/src/Tools/psxfileconv/src/images/mod.rs @@ -3,4 +3,147 @@ pub mod color_clut; pub mod color_full16; pub mod reduced_tim; pub mod tim; -pub mod types; \ No newline at end of file +pub mod types; + +use args::{ColorType, ClutAlignment}; +use color_clut::{IndexedImage, OutputType}; +use color_full16::{RgbaImage, RgbImage}; +use types::{Color as PSXColor, PSXImageConverter}; +use image::{DynamicImage, io::Reader as ImageReader}; +use std::io::{Cursor, Write}; +use tool_helper::{Error, Input}; +use reduced_tim::types::Header; + +fn modify_palette(mut image: IndexedImage, clut_align: ClutAlignment, semi_transparent: bool, transparent_palette: bool) -> IndexedImage { + if semi_transparent { + for color in image.palette.iter_mut() { + *color = PSXColor::semi_transparent(color.get_red(), color.get_green(), color.get_blue()); + } + } + + if transparent_palette { + if clut_align == ClutAlignment::Block { + for color in image.palette.iter_mut().step_by(16) { + *color = PSXColor::transparent(); + } + } + + else { + if let Some(first_color) = image.palette.get_mut(0) { + *first_color = PSXColor::transparent(); + } + } + } + image +} + +fn encode(image: T, color_depth: ColorType, clut_align: ClutAlignment, output: &mut dyn Write) -> Result<(), Error> { + let (width, height) = { + fn return_error(clut_type: u32, div: u32, width: u16, height: u16) -> Result<(u16, u16), Error> { + return Err(Error::from_callback(|| {format!("CLUT {} images require a width divideable by {} (found width: {}/{}={}, height: {})", clut_type, div, width, div, (width as f32/div as f32), height)})); + } + + let width = image.width(); + let height = image.height(); + match color_depth { + ColorType::Clut4 => { + if width & 3 == 0 { + Ok((width/4, height)) + } + + else { + return_error(4, 4, width, height) + } + }, + ColorType::Clut8 => { + if width & 1 == 0 { + Ok((width/2, height)) + } + + else { + return_error(8, 2, width, height) + } + }, + ColorType::Full16 => { + Ok((width, height)) + } + } + }?; + let palette = image.get_palette(); + let (pal_width, pal_height) = { + if let Some(palette) = &palette { + let pal_length_adjusted = { + let pal_length = palette.len(); + if pal_length <= 16 { + 16u16 + } + + else { + 256u16 + } + }; + match clut_align { + ClutAlignment::None | + ClutAlignment::Linear => (pal_length_adjusted, 1u16), + ClutAlignment::Block => (16u16, pal_length_adjusted/16u16), + } + } + + else { + (0u16, 0u16) + } + }; + + let header = Header::encode(width, height, pal_width, pal_height).ok_or(Error::from_callback(|| {format!("Image size (width: {}, height: {}) needs to be even", width, height)}))?; + + tool_helper::raw::write_raw(output, &header)?; + if let Some(palette) = palette { + let mut color_count = pal_width*pal_height; + for color in palette { + tool_helper::raw::write_raw(output, color)?; + color_count -= 1; + } + + while color_count > 0 { + tool_helper::raw::write_raw(output, &PSXColor::black())?; + color_count -= 1; + } + } + + for color in image { + tool_helper::raw::write_raw(output, &color)?; + } + + Ok(()) +} + +fn convert_full16(input: Input, output: &mut dyn Write) -> Result<(), Error> { + match ImageReader::new(Cursor::new(tool_helper::input_to_vec(input)?)).with_guessed_format()?.decode() { + Ok(image) => { + match image { + DynamicImage::ImageRgb8(image) => encode(RgbImage::new(image), ColorType::Full16, ClutAlignment::None, output), + DynamicImage::ImageRgba8(image) => encode(RgbaImage::new(image), ColorType::Full16, ClutAlignment::None, output), + + _ => Err(Error::from_str("Only RGB and RGBA images are supported for 16bit encoding")) + } + }, + Err(error) => Err(Error::from_error(error)) + } +} + +fn convert_palette_based(input: Input, output: &mut dyn Write, color_type: ColorType, clut_align: ClutAlignment, semi_transparent: bool, transparent_palette: bool) -> Result<(), Error> { + match png::Decoder::new(input).read_info() { + Ok(reader) => { + let output_type = { + match color_type { + ColorType::Clut4 => OutputType::FourBit, + ColorType::Clut8 => OutputType::EightBit, + _ => return Err(Error::from_str("ColorType not supported")) + } + }; + + encode(modify_palette(IndexedImage::new(reader, output_type)?, clut_align, semi_transparent, transparent_palette), color_type, clut_align, output) + }, + Err(error) => Err(Error::from_error(error)) + } +} \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/images/reduced_tim/mod.rs b/src/Tools/psxfileconv/src/images/reduced_tim/mod.rs index 46a73b49..446579f1 100644 --- a/src/Tools/psxfileconv/src/images/reduced_tim/mod.rs +++ b/src/Tools/psxfileconv/src/images/reduced_tim/mod.rs @@ -1,150 +1,14 @@ -use super::args::{ColorType, ClutAlignment}; -use super::color_clut::{IndexedImage, OutputType}; -use super::color_full16::{RgbaImage, RgbImage}; -use super::types::{Header, Color as PSXColor, PSXImageConverter}; -use image::{DynamicImage, io::Reader as ImageReader}; -use std::io::{Cursor, Write}; +pub mod types; + +use super::args::ColorType; +use std::io::Write; use tool_helper::{Error, Input}; pub type Arguments = super::args::Arguments; -fn modify_palette(mut image: IndexedImage, clut_align: ClutAlignment, semi_transparent: bool, transparent_palette: bool) -> IndexedImage { - if semi_transparent { - for color in image.palette.iter_mut() { - *color = PSXColor::semi_transparent(color.get_red(), color.get_green(), color.get_blue()); - } - } - - if transparent_palette { - if clut_align == ClutAlignment::Block { - for color in image.palette.iter_mut().step_by(16) { - *color = PSXColor::transparent(); - } - } - - else { - if let Some(first_color) = image.palette.get_mut(0) { - *first_color = PSXColor::transparent(); - } - } - } - image -} - -fn encode(image: T, color_depth: ColorType, clut_align: ClutAlignment, output: &mut dyn Write) -> Result<(), Error> { - let (width, height) = { - fn return_error(clut_type: u32, div: u32, width: u16, height: u16) -> Result<(u16, u16), Error> { - return Err(Error::from_callback(|| {format!("CLUT {} images require a width divideable by {} (found width: {}/{}={}, height: {})", clut_type, div, width, div, (width as f32/div as f32), height)})); - } - - let width = image.width(); - let height = image.height(); - match color_depth { - ColorType::Clut4 => { - if width & 3 == 0 { - Ok((width/4, height)) - } - - else { - return_error(4, 4, width, height) - } - }, - ColorType::Clut8 => { - if width & 1 == 0 { - Ok((width/2, height)) - } - - else { - return_error(8, 2, width, height) - } - }, - ColorType::Full16 => { - Ok((width, height)) - } - } - }?; - let palette = image.get_palette(); - let (pal_width, pal_height) = { - if let Some(palette) = &palette { - let pal_length_adjusted = { - let pal_length = palette.len(); - if pal_length <= 16 { - 16u16 - } - - else { - 256u16 - } - }; - match clut_align { - ClutAlignment::None | - ClutAlignment::Linear => (pal_length_adjusted, 1u16), - ClutAlignment::Block => (16u16, pal_length_adjusted/16u16), - } - } - - else { - (0u16, 0u16) - } - }; - - let header = Header::encode(width, height, pal_width, pal_height).ok_or(Error::from_callback(|| {format!("Image size (width: {}, height: {}) needs to be even", width, height)}))?; - - tool_helper::raw::write_raw(output, &header)?; - if let Some(palette) = palette { - let mut color_count = pal_width*pal_height; - for color in palette { - tool_helper::raw::write_raw(output, color)?; - color_count -= 1; - } - - while color_count > 0 { - tool_helper::raw::write_raw(output, &PSXColor::black())?; - color_count -= 1; - } - } - - for color in image { - tool_helper::raw::write_raw(output, &color)?; - } - - Ok(()) -} - -fn convert_full16(input: Input, output: &mut dyn Write) -> Result<(), Error> { - match ImageReader::new(Cursor::new(tool_helper::input_to_vec(input)?)).with_guessed_format()?.decode() { - Ok(image) => { - match image { - DynamicImage::ImageRgb8(image) => encode(RgbImage::new(image), ColorType::Full16, ClutAlignment::None, output), - DynamicImage::ImageRgba8(image) => encode(RgbaImage::new(image), ColorType::Full16, ClutAlignment::None, output), - - _ => Err(Error::from_str("Only RGB and RGBA images are supported for 16bit encoding")) - } - }, - Err(error) => Err(Error::from_error(error)) - } -} - -fn convert_palette_based(input: Input, output: &mut dyn Write, color_type: ColorType, clut_align: ClutAlignment, semi_transparent: bool, transparent_palette: bool) -> Result<(), Error> { - match png::Decoder::new(input).read_info() { - Ok(reader) => { - let output_type = { - match color_type { - ColorType::Clut4 => OutputType::FourBit, - ColorType::Clut8 => OutputType::EightBit, - _ => return Err(Error::from_str("ColorType not supported")) - } - }; - - encode(modify_palette(IndexedImage::new(reader, output_type)?, clut_align, semi_transparent, transparent_palette), color_type, clut_align, output) - }, - Err(error) => Err(Error::from_error(error)) - } -} - pub fn convert(args: Arguments, input: Input, output: &mut dyn Write) -> Result<(), Error> { match args.color_depth { - ColorType::Full16 => convert_full16(input, output), - _ => convert_palette_based(input, output, args.color_depth, args.clut_align, args.semi_transparent, args.transparent_palette), + ColorType::Full16 => super::convert_full16(input, output), + _ => super::convert_palette_based(input, output, args.color_depth, args.clut_align, args.semi_transparent, args.transparent_palette), } } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/images/reduced_tim/types.rs b/src/Tools/psxfileconv/src/images/reduced_tim/types.rs new file mode 100644 index 00000000..17b355c2 --- /dev/null +++ b/src/Tools/psxfileconv/src/images/reduced_tim/types.rs @@ -0,0 +1,38 @@ +use super::super::types::set_member_value; +use tool_helper::{bits::BitRange, raw::RawConversion}; + +#[repr(packed(1))] +#[allow(dead_code)] +pub struct Header { + value: u32 +} + +#[allow(dead_code)] +impl Header { + const TEX_WIDTH_BIT_RANGE: BitRange = BitRange::from_to(0, 8); + const TEX_HEIGHT_BIT_RANGE: BitRange = BitRange::from_to(9, 16); + const CLUT_WIDTH_BIT_RANGE: BitRange = BitRange::from_to(17, 22); + const CLUT_HEIGHT_BIT_RANGE: BitRange = BitRange::from_to(23, 31); + + pub fn encode(tex_width: u16, tex_height: u16, clut_width: u16, clut_height: u16) -> Option
{ + if tex_width & 1 == 1 || tex_height & 1 == 1 { + None + } + + else { + let value = set_member_value!(set_member_value!(set_member_value!(set_member_value!(0, + tex_width, 1, u32), + tex_height, 1, u32), + clut_width, 4, u32), + clut_height, 0, u32); + + Some(Header{value}) + } + } +} + +impl RawConversion<4> for Header { + fn convert_to_raw(&self) -> [u8; 4] { + self.value.to_le_bytes() + } +} \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/images/types.rs b/src/Tools/psxfileconv/src/images/types.rs index 44f356d2..dc3135eb 100644 --- a/src/Tools/psxfileconv/src/images/types.rs +++ b/src/Tools/psxfileconv/src/images/types.rs @@ -6,20 +6,16 @@ pub struct Color { value: u16 } -#[repr(packed(1))] -#[allow(dead_code)] -pub struct Header { - value: u32 -} - macro_rules! set_member_value { ($dst:expr, $color:ident, $shift:expr, $bits:ident) => { paste::item! { - bits::[< set_value_ $bits >]($dst, ($color >> $shift) as $bits, &Self::[< $color:upper _BIT_RANGE >]) + tool_helper::bits::[< set_value_ $bits >]($dst, ($color >> $shift) as $bits, &Self::[< $color:upper _BIT_RANGE >]) } }; } +pub(crate) use set_member_value; + macro_rules! make_member_getter_setter { ($color:ident, $shift:expr, $bits:ident) => { paste::item! { @@ -124,36 +120,6 @@ impl RawConversion<2> for Color { } } -#[allow(dead_code)] -impl Header { - const TEX_WIDTH_BIT_RANGE: BitRange = BitRange::from_to(0, 8); - const TEX_HEIGHT_BIT_RANGE: BitRange = BitRange::from_to(9, 16); - const CLUT_WIDTH_BIT_RANGE: BitRange = BitRange::from_to(17, 22); - const CLUT_HEIGHT_BIT_RANGE: BitRange = BitRange::from_to(23, 31); - - pub fn encode(tex_width: u16, tex_height: u16, clut_width: u16, clut_height: u16) -> Option
{ - if tex_width & 1 == 1 || tex_height & 1 == 1 { - None - } - - else { - let value = set_member_value!(set_member_value!(set_member_value!(set_member_value!(0, - tex_width, 1, u32), - tex_height, 1, u32), - clut_width, 4, u32), - clut_height, 0, u32); - - Some(Header{value}) - } - } -} - -impl RawConversion<4> for Header { - fn convert_to_raw(&self) -> [u8; 4] { - self.value.to_le_bytes() - } -} - pub trait PSXImageConverter: std::iter::Iterator { fn width(&self) -> u16; fn height(&self) -> u16;