diff --git a/src/Tools/psxfileconv/src/images/mod.rs b/src/Tools/psxfileconv/src/images/mod.rs index 478b4fbc..95ca5119 100644 --- a/src/Tools/psxfileconv/src/images/mod.rs +++ b/src/Tools/psxfileconv/src/images/mod.rs @@ -93,7 +93,7 @@ fn encode(header_conv: &mut dyn HeaderEncoder, image: T, c } }; - header_conv.encode_settings(width, height, pal_width, pal_height)?; + header_conv.encode_settings(color_depth, width, height, pal_width, pal_height)?; header_conv.write_header(output)?; header_conv.write_clut_header(output)?; diff --git a/src/Tools/psxfileconv/src/images/reduced_tim/types.rs b/src/Tools/psxfileconv/src/images/reduced_tim/types.rs index 25190040..e1d58363 100644 --- a/src/Tools/psxfileconv/src/images/reduced_tim/types.rs +++ b/src/Tools/psxfileconv/src/images/reduced_tim/types.rs @@ -1,9 +1,8 @@ -use super::super::types::{HeaderEncoder, set_member_value}; +use super::super::{args::ColorType, types::{HeaderEncoder, set_member_value}}; use std::io::Write; use tool_helper::{bits::BitRange, raw::RawConversion, Error}; #[repr(packed(1))] -#[allow(dead_code)] pub struct Header { value: u32 } @@ -22,7 +21,7 @@ impl Default for Header { } impl HeaderEncoder for Header { - fn encode_settings(&mut self, tex_width: u16, tex_height: u16, clut_width: u16, clut_height: u16) -> Result<(), Error> { + fn encode_settings(&mut self, _color_type: ColorType, tex_width: u16, tex_height: u16, clut_width: u16, clut_height: u16) -> Result<(), Error> { if tex_width & 1 == 1 || tex_height & 1 == 1 { Err(Error::from_text(format!("Image size (width: {}, height: {}) needs to be even", tex_width, tex_height))) } diff --git a/src/Tools/psxfileconv/src/images/tim/mod.rs b/src/Tools/psxfileconv/src/images/tim/mod.rs index e69de29b..f1e08d38 100644 --- a/src/Tools/psxfileconv/src/images/tim/mod.rs +++ b/src/Tools/psxfileconv/src/images/tim/mod.rs @@ -0,0 +1,16 @@ +pub mod types; + +use super::args::ColorType; +use std::io::Write; +use types::Header; +use tool_helper::{Error, Input}; + +pub type Arguments = super::args::Arguments; + +pub fn convert(args: Arguments, input: Input, output: &mut dyn Write) -> Result<(), Error> { + let mut header_conv = Header::default(); + match args.color_depth { + ColorType::Full16 => super::convert_full16(&mut header_conv, input, output), + _ => super::convert_palette_based(&mut header_conv, 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/tim/types.rs b/src/Tools/psxfileconv/src/images/tim/types.rs new file mode 100644 index 00000000..819a4d98 --- /dev/null +++ b/src/Tools/psxfileconv/src/images/tim/types.rs @@ -0,0 +1,90 @@ +use super::super::{args::ColorType, types::HeaderEncoder}; +use std::io::Write; +use tool_helper::{bits::{Bit, BitRange}, raw::RawConversion, Error}; + + +pub struct Header { + flag: u32, + clut_block: DataBlock, + pixel_block: DataBlock, +} + +impl Header { + const ID_VALUE: u32 = BitRange::from_to(0, 7).as_value(0x10) as u32; + const ID_VERSION_VALUE:u32 = BitRange::from_to(8, 15).as_value(0x0) as u32; + + const FLAG_PMODE_BIT_RANGE: BitRange = BitRange::from_to(0, 2); + const FLAG_CF_BIT: Bit = Bit::at(3); + + const ID:u32 = Self::ID_VALUE | Self::ID_VERSION_VALUE; +} + +impl Default for Header { + fn default() -> Self { + Header{flag: 0, clut_block: DataBlock::default(), pixel_block: DataBlock::default()} + } +} + +impl HeaderEncoder for Header { + fn encode_settings(&mut self, color_type: ColorType, tex_width: u16, tex_height: u16, clut_width: u16, clut_height: u16) -> Result<(), Error> { + self.flag = match color_type { + ColorType::Clut4 => (Self::FLAG_PMODE_BIT_RANGE.as_value(0x0) | Self::FLAG_CF_BIT.as_value(true)) as u32, + ColorType::Clut8 => (Self::FLAG_PMODE_BIT_RANGE.as_value(0x1) | Self::FLAG_CF_BIT.as_value(true)) as u32, + ColorType::Full16 => (Self::FLAG_PMODE_BIT_RANGE.as_value(0x2) | Self::FLAG_CF_BIT.as_value(true)) as u32, + }; + + // TODO: Support tex & clut x/y + self.clut_block = DataBlock::new(0, 0, clut_width, clut_height); + self.pixel_block = DataBlock::new(0, 0, tex_width, tex_height); + Ok(()) + } + + fn write_header(&self, output: &mut dyn Write) -> Result { + let bytes = output.write(&Header::ID.to_le_bytes())?; + Ok(bytes + output.write(&self.flag.to_le_bytes())?) + } + + fn write_clut_header(&self, output: &mut dyn Write) -> Result { + Ok(output.write(&self.clut_block.convert_to_raw())?) + } + + fn write_pixel_header(&self, output: &mut dyn Write) -> Result { + Ok(output.write(&self.pixel_block.convert_to_raw())?) + } +} + +pub struct DataBlock { + bytes: u32, + x: u16, + y: u16, + w: u16, + h: u16, +} + +impl DataBlock { + const RAW_HEADER_SIZE: usize = (4*std::mem::size_of::()) + std::mem::size_of::(); + + pub fn new(x: u16, y: u16, w: u16, h: u16) -> DataBlock { + let bytes = ((w as usize*h as usize) + Self::RAW_HEADER_SIZE) as u32; + DataBlock{bytes, x, y, w, h} + } +} + +impl std::default::Default for DataBlock { + fn default() -> Self { + DataBlock{bytes: 0, x: 0, y: 0, w: 0, h: 0} + } +} + +impl RawConversion<{Self::RAW_HEADER_SIZE}> for DataBlock { + fn convert_to_raw(&self) -> [u8; Self::RAW_HEADER_SIZE] { + let mut raw = [0u8; Self::RAW_HEADER_SIZE]; + + raw[ 0..4].copy_from_slice(&self.bytes.to_le_bytes()); + raw[ 4..6].copy_from_slice(&self.y.to_le_bytes()); + raw[ 6..8].copy_from_slice(&self.x.to_le_bytes()); + raw[ 8..10].copy_from_slice(&self.h.to_le_bytes()); + raw[10..12].copy_from_slice(&self.w.to_le_bytes()); + raw + } +} \ 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 42ef9597..5015e14b 100644 --- a/src/Tools/psxfileconv/src/images/types.rs +++ b/src/Tools/psxfileconv/src/images/types.rs @@ -25,6 +25,8 @@ macro_rules! make_member_getter_setter { pub(crate) use set_member_value; +use super::args; + #[repr(packed(1))] #[allow(dead_code)] pub struct Color { @@ -122,10 +124,10 @@ impl RawConversion<2> for Color { } pub trait HeaderEncoder { - fn encode_settings(&mut self, tex_width: u16, tex_height: u16, clut_width: u16, clut_height: u16) -> Result<(), Error>; - fn write_header(&self, output: &mut dyn Write) -> Result; - fn write_clut_header(&self, output: &mut dyn Write) -> Result; - fn write_pixel_header(&self, output: &mut dyn Write) -> Result; + fn encode_settings(&mut self, color_type: args::ColorType, tex_width: u16, tex_height: u16, clut_width: u16, clut_height: u16) -> Result<(), Error>; + fn write_header(&self, output: &mut dyn Write) -> Result; + fn write_clut_header(&self, output: &mut dyn Write) -> Result; + fn write_pixel_header(&self, output: &mut dyn Write) -> Result; } pub trait PSXImageConverter: std::iter::Iterator { diff --git a/src/Tools/tool_helper/Cargo.toml b/src/Tools/tool_helper/Cargo.toml index 685cdc1c..1e46a6b5 100644 --- a/src/Tools/tool_helper/Cargo.toml +++ b/src/Tools/tool_helper/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tool_helper" -version = "0.9.7" +version = "0.9.8" edition = "2021" [profile.release] diff --git a/src/Tools/tool_helper/src/bits.rs b/src/Tools/tool_helper/src/bits.rs index f68fc377..013e19a5 100644 --- a/src/Tools/tool_helper/src/bits.rs +++ b/src/Tools/tool_helper/src/bits.rs @@ -16,8 +16,12 @@ impl BitRange { (1 << self.length) - 1 } + pub const fn as_value(&self, value: usize) -> usize { + (value & self.get_mask()) << self.start + } + pub const fn or_value(&self, dst_value: usize, value: usize) -> usize { - dst_value | ((value & self.get_mask()) << self.start) + dst_value | self.as_value(value) } } @@ -30,9 +34,19 @@ impl Bit { Bit{pos} } + pub const fn as_value(&self, is_set: bool) -> usize { + if is_set { + 1 << self.pos + } + + else { + 0 + } + } + pub const fn or_value(&self, dst_value: usize, is_set: bool) -> usize { if is_set { - dst_value | (1 << self.pos) + dst_value | self.as_value(is_set) } else {