mirror of
https://github.com/redstrate/Physis.git
synced 2025-04-23 13:17:44 +00:00
Decompress and return rgba data for textures
This commit is contained in:
parent
0210479fd3
commit
6554dee2f1
4 changed files with 79 additions and 59 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -351,6 +351,12 @@ version = "0.2.127"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b"
|
checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libm"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "292a948cd991e376cf75541fe5b97a1081d713c618b4f1b9500f8844e49eb565"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libz-sys"
|
name = "libz-sys"
|
||||||
version = "1.1.8"
|
version = "1.1.8"
|
||||||
|
@ -452,6 +458,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha1_smol",
|
"sha1_smol",
|
||||||
|
"texpresso",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -647,6 +654,15 @@ dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "texpresso"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8277e703c934b9693d0773d5749faacc6366b3d81d012da556a4cfd4ab87f336"
|
||||||
|
dependencies = [
|
||||||
|
"libm",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.15.0"
|
version = "0.15.0"
|
||||||
|
|
|
@ -52,4 +52,7 @@ sha1_smol = "1.0.0"
|
||||||
glam = "0.21.3"
|
glam = "0.21.3"
|
||||||
|
|
||||||
# needed for c-style bitflags used in some formats (such as tex files)
|
# needed for c-style bitflags used in some formats (such as tex files)
|
||||||
bitflags = "1.3"
|
bitflags = "1.3"
|
||||||
|
|
||||||
|
# needed for dxt/bc decompression
|
||||||
|
texpresso = "2.0.1"
|
25
src/dat.rs
25
src/dat.rs
|
@ -28,7 +28,7 @@ struct StandardFileBlock {
|
||||||
num_blocks: u32,
|
num_blocks: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BinRead)]
|
#[derive(BinRead, Debug)]
|
||||||
struct TextureLodBlock {
|
struct TextureLodBlock {
|
||||||
compressed_offset: u32,
|
compressed_offset: u32,
|
||||||
compressed_size: u32,
|
compressed_size: u32,
|
||||||
|
@ -88,7 +88,7 @@ pub struct ModelFileBlock {
|
||||||
pub edge_geometry_enabled: bool,
|
pub edge_geometry_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BinRead)]
|
#[derive(BinRead, Debug)]
|
||||||
struct TextureBlock {
|
struct TextureBlock {
|
||||||
#[br(pad_before = 8)]
|
#[br(pad_before = 8)]
|
||||||
num_blocks: u32,
|
num_blocks: u32,
|
||||||
|
@ -103,7 +103,7 @@ struct TextureBlock {
|
||||||
struct FileInfo {
|
struct FileInfo {
|
||||||
size: u32,
|
size: u32,
|
||||||
file_type: FileType,
|
file_type: FileType,
|
||||||
file_size: i32,
|
file_size: u32,
|
||||||
|
|
||||||
#[br(if (file_type == FileType::Standard))]
|
#[br(if (file_type == FileType::Standard))]
|
||||||
standard_info: Option<StandardFileBlock>,
|
standard_info: Option<StandardFileBlock>,
|
||||||
|
@ -331,12 +331,15 @@ impl DatFile {
|
||||||
let texture_file_info = file_info.texture_info.as_ref().unwrap();
|
let texture_file_info = file_info.texture_info.as_ref().unwrap();
|
||||||
|
|
||||||
// write the header if it exists
|
// write the header if it exists
|
||||||
if texture_file_info.lods[0].compressed_offset != 0 {
|
let mipmap_size = texture_file_info.lods[0].compressed_size;
|
||||||
let original_pos = self.file.stream_position().unwrap();
|
if mipmap_size != 0 {
|
||||||
|
let original_pos = self.file.stream_position().ok()?;
|
||||||
|
|
||||||
self.file.seek(SeekFrom::Start(offset + file_info.size as u64)).ok()?;
|
self.file.seek(SeekFrom::Start(offset + file_info.size as u64)).ok()?;
|
||||||
|
|
||||||
let mut header = vec![0u8; texture_file_info.lods[0].compressed_offset as usize];
|
let mut header = vec![0u8; texture_file_info.lods[0].compressed_offset as usize];
|
||||||
self.file.read(&mut header).ok()?;
|
self.file.read_exact(&mut header).ok()?;
|
||||||
|
|
||||||
data.append(&mut header);
|
data.append(&mut header);
|
||||||
|
|
||||||
self.file.seek(SeekFrom::Start(original_pos)).ok()?;
|
self.file.seek(SeekFrom::Start(original_pos)).ok()?;
|
||||||
|
@ -346,9 +349,13 @@ impl DatFile {
|
||||||
let mut running_block_total = (texture_file_info.lods[i as usize].compressed_offset as u64) + offset + (file_info.size as u64);
|
let mut running_block_total = (texture_file_info.lods[i as usize].compressed_offset as u64) + offset + (file_info.size as u64);
|
||||||
|
|
||||||
for _ in 0..texture_file_info.lods[i as usize].block_count {
|
for _ in 0..texture_file_info.lods[i as usize].block_count {
|
||||||
data.append(&mut read_data_block(&self.file, running_block_total).unwrap());
|
let original_pos = self.file.stream_position().ok()?;
|
||||||
self.file.seek(SeekFrom::Start(running_block_total)).ok()?;
|
|
||||||
running_block_total += i16::read(&mut self.file).unwrap() as u64;
|
data.append(&mut read_data_block(&self.file, running_block_total)?);
|
||||||
|
|
||||||
|
self.file.seek(SeekFrom::Start(original_pos)).ok()?;
|
||||||
|
|
||||||
|
running_block_total += i16::read(&mut self.file).ok()? as u64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
92
src/tex.rs
92
src/tex.rs
|
@ -1,8 +1,10 @@
|
||||||
use std::io::Cursor;
|
use std::cmp::min;
|
||||||
|
use std::io::{Cursor, Read, Seek, SeekFrom};
|
||||||
use binrw::binread;
|
use binrw::binread;
|
||||||
use crate::gamedata::MemoryBuffer;
|
use crate::gamedata::MemoryBuffer;
|
||||||
use binrw::BinRead;
|
use binrw::BinRead;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
use texpresso::Format;
|
||||||
|
|
||||||
// Attributes and Format are adapted from Lumina (https://github.com/NotAdam/Lumina/blob/master/src/Lumina/Data/Files/TexFile.cs)
|
// Attributes and Format are adapted from Lumina (https://github.com/NotAdam/Lumina/blob/master/src/Lumina/Data/Files/TexFile.cs)
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
@ -35,51 +37,13 @@ bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
#[binread]
|
||||||
#[binread]
|
#[br(repr = u32)]
|
||||||
struct TextureFormat : u32 {
|
#[derive(Debug)]
|
||||||
const TypeShift = 0xC;
|
enum TextureFormat {
|
||||||
const TypeMask = 0xF000;
|
B8G8R8A8 = 0x1450,
|
||||||
const ComponentShift = 0x8;
|
BC1 = 0x3420,
|
||||||
const ComponentMask = 0xF00;
|
BC5 = 0x3431
|
||||||
const BppShift = 0x4;
|
|
||||||
const BppMask = 0xF0;
|
|
||||||
const EnumShift = 0x0;
|
|
||||||
const EnumMask = 0xF;
|
|
||||||
const TypeInteger = 0x1;
|
|
||||||
const TypeFloat = 0x2;
|
|
||||||
const TypeDxt = 0x3;
|
|
||||||
const TypeBc123 = 0x3;
|
|
||||||
const TypeDepthStencil = 0x4;
|
|
||||||
const TypeSpecial = 0x5;
|
|
||||||
const TypeBc57 = 0x6;
|
|
||||||
|
|
||||||
const L8 = 0x1130;
|
|
||||||
const A8 = 0x1131;
|
|
||||||
const B4G4R4A4 = 0x1440;
|
|
||||||
const B5G5R5A1 = 0x1441;
|
|
||||||
const B8G8R8A8 = 0x1450;
|
|
||||||
const B8G8R8X8 = 0x1451;
|
|
||||||
|
|
||||||
const R32F = 0x2150;
|
|
||||||
const R16G16F = 0x2250;
|
|
||||||
const R32G32F = 0x2260;
|
|
||||||
const R16G16B16A16F = 0x2460;
|
|
||||||
const R32G32B32A32F = 0x2470;
|
|
||||||
|
|
||||||
const BC1 = 0x3420;
|
|
||||||
const BC2 = 0x3430;
|
|
||||||
const BC3 = 0x3431;
|
|
||||||
const BC5 = 0x6230;
|
|
||||||
const BC7 = 0x6432;
|
|
||||||
|
|
||||||
const D16 = 0x4140;
|
|
||||||
const D24S8 = 0x4250;
|
|
||||||
|
|
||||||
const Null = 0x5100;
|
|
||||||
const Shadow16 = 0x5140;
|
|
||||||
const Shadow24 = 0x5150;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binread]
|
#[binread]
|
||||||
|
@ -98,7 +62,7 @@ struct TexHeader {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Texture {
|
pub struct Texture {
|
||||||
|
rgba: Vec<u8>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Texture {
|
impl Texture {
|
||||||
|
@ -106,8 +70,38 @@ impl Texture {
|
||||||
let mut cursor = Cursor::new(buffer);
|
let mut cursor = Cursor::new(buffer);
|
||||||
let header = TexHeader::read(&mut cursor).unwrap();
|
let header = TexHeader::read(&mut cursor).unwrap();
|
||||||
|
|
||||||
println!("{:#?}", header);
|
// TODO: Adapted from Lumina, but this really can be written better...
|
||||||
|
let mut texture_data_size = vec![];
|
||||||
|
texture_data_size.resize(min(13, header.mip_levels as usize), 0);
|
||||||
|
let size = texture_data_size.len();
|
||||||
|
for i in 0..size - 1 {
|
||||||
|
texture_data_size[i] = header.offset_to_surface[i + 1] - header.offset_to_surface[i];
|
||||||
|
}
|
||||||
|
texture_data_size[size - 1] = (buffer.len() - header.offset_to_surface[size - 1] as usize) as u32;
|
||||||
|
|
||||||
None
|
cursor.seek(SeekFrom::Start(header.offset_to_surface[0] as u64)).ok()?;
|
||||||
|
|
||||||
|
let mut src = vec![0u8; texture_data_size.iter().sum::<u32>() as usize];
|
||||||
|
cursor.read_exact(src.as_mut_slice()).ok()?;
|
||||||
|
|
||||||
|
let mut dst : Vec<u8> = vec![0u8; (header.width as usize * header.height as usize * 4) as usize];
|
||||||
|
|
||||||
|
match header.format {
|
||||||
|
TextureFormat::B8G8R8A8 => {
|
||||||
|
dst.copy_from_slice(&src);
|
||||||
|
}
|
||||||
|
TextureFormat::BC1 => {
|
||||||
|
let format = Format::Bc1;
|
||||||
|
format.decompress(&src, header.width as usize, header.height as usize, dst.as_mut_slice());
|
||||||
|
}
|
||||||
|
TextureFormat::BC5 => {
|
||||||
|
let format = Format::Bc3;
|
||||||
|
format.decompress(&src, header.width as usize, header.height as usize, dst.as_mut_slice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Texture {
|
||||||
|
rgba: dst
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue