jmmt: add texture formats
This commit also adds a skeleton for a texture tool.
This commit is contained in:
parent
094c14a799
commit
69e82236c6
|
@ -1,7 +1,8 @@
|
|||
[workspace]
|
||||
#resolver = "2"
|
||||
members = [
|
||||
"crates/jmmt",
|
||||
"crates/jmrenamer"
|
||||
# "crates/paktool"
|
||||
"crates/jmmt",
|
||||
"crates/jmrenamer",
|
||||
"crates/textool"
|
||||
# "crates/paktool"
|
||||
]
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -10,3 +10,6 @@ pub mod lzss;
|
|||
// higher level I/O?
|
||||
// pub mod read;
|
||||
// pub mod write;
|
||||
|
||||
// Maybe, using package.toc?
|
||||
// pub mod pakfs;
|
||||
|
|
|
@ -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,
|
||||
|
@ -25,4 +26,4 @@ impl Validatable for LzssHeader {
|
|||
fn valid(&self) -> bool {
|
||||
self.byte_id == 0x91 && self.header_size as usize == size_of::<LzssHeader>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue