More TIM support
This commit is contained in:
parent
1673d6ef2c
commit
3b3b2ecfc4
|
@ -93,7 +93,7 @@ fn encode<T: PSXImageConverter>(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_header(output)?;
|
||||||
header_conv.write_clut_header(output)?;
|
header_conv.write_clut_header(output)?;
|
||||||
|
|
|
@ -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 std::io::Write;
|
||||||
use tool_helper::{bits::BitRange, raw::RawConversion, Error};
|
use tool_helper::{bits::BitRange, raw::RawConversion, Error};
|
||||||
|
|
||||||
#[repr(packed(1))]
|
#[repr(packed(1))]
|
||||||
#[allow(dead_code)]
|
|
||||||
pub struct Header {
|
pub struct Header {
|
||||||
value: u32
|
value: u32
|
||||||
}
|
}
|
||||||
|
@ -22,7 +21,7 @@ impl Default for Header {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeaderEncoder 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 {
|
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)))
|
Err(Error::from_text(format!("Image size (width: {}, height: {}) needs to be even", tex_width, tex_height)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<usize, Error> {
|
||||||
|
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<usize, Error> {
|
||||||
|
Ok(output.write(&self.clut_block.convert_to_raw())?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_pixel_header(&self, output: &mut dyn Write) -> Result<usize, Error> {
|
||||||
|
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::<u16>()) + std::mem::size_of::<u32>();
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,6 +25,8 @@ macro_rules! make_member_getter_setter {
|
||||||
|
|
||||||
pub(crate) use set_member_value;
|
pub(crate) use set_member_value;
|
||||||
|
|
||||||
|
use super::args;
|
||||||
|
|
||||||
#[repr(packed(1))]
|
#[repr(packed(1))]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct Color {
|
pub struct Color {
|
||||||
|
@ -122,10 +124,10 @@ impl RawConversion<2> for Color {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait HeaderEncoder {
|
pub trait HeaderEncoder {
|
||||||
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: 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<usize, Error>;
|
fn write_header(&self, output: &mut dyn Write) -> Result<usize, Error>;
|
||||||
fn write_clut_header(&self, output: &mut dyn Write) -> Result<usize, Error>;
|
fn write_clut_header(&self, output: &mut dyn Write) -> Result<usize, Error>;
|
||||||
fn write_pixel_header(&self, output: &mut dyn Write) -> Result<usize, Error>;
|
fn write_pixel_header(&self, output: &mut dyn Write) -> Result<usize, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PSXImageConverter: std::iter::Iterator<Item = Color> {
|
pub trait PSXImageConverter: std::iter::Iterator<Item = Color> {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "tool_helper"
|
name = "tool_helper"
|
||||||
version = "0.9.7"
|
version = "0.9.8"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|
|
@ -16,8 +16,12 @@ impl BitRange {
|
||||||
(1 << self.length) - 1
|
(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 {
|
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}
|
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 {
|
pub const fn or_value(&self, dst_value: usize, is_set: bool) -> usize {
|
||||||
if is_set {
|
if is_set {
|
||||||
dst_value | (1 << self.pos)
|
dst_value | self.as_value(is_set)
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
|
Loading…
Reference in New Issue