jmmt: add texture formats

This commit also adds a skeleton for a texture tool.
This commit is contained in:
Lily Tsuru 2023-06-26 05:56:27 -04:00
parent 094c14a799
commit 69e82236c6
10 changed files with 195 additions and 6 deletions

View File

@ -1,7 +1,8 @@
[workspace]
#resolver = "2"
members = [
"crates/jmmt",
"crates/jmrenamer"
# "crates/paktool"
"crates/jmmt",
"crates/jmrenamer",
"crates/textool"
# "crates/paktool"
]

View File

@ -1,10 +1,37 @@
//! Low-level structure definitions
//! Low-level file format definitions. These are suitable for usage with the [binext] crate,
//! which just so happens to be a dependency of this crate! Funny how things work.
pub mod package;
pub mod package_toc;
pub mod ps2_texture;
pub mod ps2_palette;
/// A trait validatable format objects should implement.
/// TODO: integrate this with some FourCC crate, or re-invent the wheel.
pub trait Validatable {
/// Returns true if the object is valid, false otherwise.
fn valid(&self) -> bool;
}
/// Make a Rust [String] from a byte slice that came from a C string/structure.
///
/// # Usage
///
/// The byte slice has to be a valid UTF-8 string.
/// (Note that in most cases, ASCII strings are valid UTF-8, so this isn't something you'll particularly
/// have to worry about).
///
/// # Safety
///
/// This function does not directly make use of any unsafe Rust code.
pub fn make_c_string(bytes: &[u8]) -> Option<String> {
let bytes_without_null = match bytes.iter().position(|&b| b == 0) {
Some(ix) => &bytes[..ix],
None => bytes,
};
match std::str::from_utf8(bytes_without_null).ok() {
Some(string) => Some(String::from(string)),
None => None
}
}

View File

@ -18,6 +18,7 @@ pub struct PackageEofHeader {
/// A Package Group. I have no idea what this is yet
#[repr(C)]
#[derive(Debug, Default)]
pub struct PackageGroup {
pub fourcc: u32,
@ -44,6 +45,7 @@ impl Validatable for PackageGroup {
/// A package file chunk.
#[repr(C)]
#[derive(Debug, Default)]
pub struct PackageFileChunk {
pub fourcc: u32,

View File

@ -1,5 +1,7 @@
//! Package.toc structures
use super::make_c_string;
/// An entry inside the `package.toc` file
#[derive(Debug)]
#[repr(C)]
@ -15,7 +17,7 @@ pub struct PackageTocEntry {
impl PackageTocEntry {
fn file_name(&self) -> Option<String> {
String::from_utf8(self.file_name.to_vec()).ok()
make_c_string(&self.file_name)
}
fn file_name_hash(&self) -> u32 {

View File

@ -0,0 +1,32 @@
//! .ps2_palette structures
use super::Validatable;
/// .ps2_palette header
#[repr(C)]
#[derive(Debug, Default)]
pub struct Ps2PaletteHeader {
pub fourcc: u32,
pub unk: u32,
pub unk2: u16,
pub color_count: u16,
pub palette_bpp: u16,
pub unk3: u16,
pub data_start: u32,
pub header_size: u32,
pub pad: [u32; 6] // reserved for game code, like .ps2_texture?
}
impl Ps2PaletteHeader {
/// 'PAL1'
pub const VALID_FOURCC : u32 = 0x314c4150;
}
impl Validatable for Ps2PaletteHeader {
fn valid(&self) -> bool {
self.fourcc == Self::VALID_FOURCC && self.header_size == 0x18
}
}

View File

@ -0,0 +1,44 @@
//! .ps2_texture structures
use super::Validatable;
/// .ps2_texture header.
#[repr(C)]
#[derive(Debug, Default)]
pub struct Ps2TextureHeader {
pub magic: u32,
pub unk: u32,
pub unk2: u16,
pub width: u16,
pub height: u16,
/// bits-per-pixel of the texture data. Anything above 8
/// will not have an associated .ps2_palette file,
/// since the texture data will not be indirect color.
pub bpp: u16,
/// Data start offset.
pub data_start_offset: u32,
/// Possibly the size of this header.
pub header_end_offset: u32,
pub unk6: [u32; 8], // mostly unrelated values, this is probably padding space for the game code to put stuff
}
impl Ps2TextureHeader {
/// 'TEX1'
pub const VALID_FOURCC: u32 = 0x31584554;
fn has_palette(&self) -> bool {
// if the BPP is less than or equal to 8 (I've only seen 8bpp and 16bpp),
// then the texture will be palettized.
self.bpp >= 8
}
}
impl Validatable for Ps2TextureHeader {
fn valid(&self) -> bool {
self.magic == Self::VALID_FOURCC && self.header_end_offset == 0x38
}
}

View File

@ -10,3 +10,6 @@ pub mod lzss;
// higher level I/O?
// pub mod read;
// pub mod write;
// Maybe, using package.toc?
// pub mod pakfs;

View File

@ -2,6 +2,7 @@ use std::mem::size_of;
use crate::format::Validatable;
#[repr(C)]
#[derive(Debug, Default)]
pub struct LzssHeader {
pub next: u32, // ps2 ptr. usually 0 cause theres no next header
pub byte_id: u8,

12
crates/textool/Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "textool"
version = "0.1.0"
edition = "2021"
[dependencies]
clap = { version = "4.3.8", features = ["derive"] }
image = "0.24.6"
jmmt = { path = "../jmmt" }
# Temporary, until the reader code is thrown into jmmt crate
binext = "1.0.0"

View File

@ -0,0 +1,65 @@
use clap::{Parser, Subcommand};
use std::default;
use std::path::Path;
use std::fs::{
File
};
use jmmt::format::{
ps2_palette::*,
ps2_texture::*
};
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[command(propagate_version = true)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Exports the texture to a .png file
Export { path: String },
//Import
}
struct ImageReader {
file: File,
header: Ps2TextureHeader,
pal_header: Ps2PaletteHeader,
image_data: Vec<u8>,
palette_data: Vec<u8>
}
impl ImageReader {
fn new(file: &mut File) -> Self {
ImageReader {
file: file.try_clone().unwrap(),
header: Ps2TextureHeader::default(),
pal_header: Ps2PaletteHeader::default(),
image_data: Vec::default(),
palette_data: Vec::default()
}
}
fn read(&mut self) -> std::io::Result<()> {
Ok(())
}
}
fn main() {
let cli = Cli::parse();
match &cli.command {
Commands::Export { path } => {
println!("exporting {}", path);
let path = Path::new(path);
}
}
}