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"
|
||||
checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "292a948cd991e376cf75541fe5b97a1081d713c618b4f1b9500f8844e49eb565"
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.8"
|
||||
|
@ -452,6 +458,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"sha1_smol",
|
||||
"texpresso",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -647,6 +654,15 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "texpresso"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8277e703c934b9693d0773d5749faacc6366b3d81d012da556a4cfd4ab87f336"
|
||||
dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.0"
|
||||
|
|
|
@ -52,4 +52,7 @@ sha1_smol = "1.0.0"
|
|||
glam = "0.21.3"
|
||||
|
||||
# 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,
|
||||
}
|
||||
|
||||
#[derive(BinRead)]
|
||||
#[derive(BinRead, Debug)]
|
||||
struct TextureLodBlock {
|
||||
compressed_offset: u32,
|
||||
compressed_size: u32,
|
||||
|
@ -88,7 +88,7 @@ pub struct ModelFileBlock {
|
|||
pub edge_geometry_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(BinRead)]
|
||||
#[derive(BinRead, Debug)]
|
||||
struct TextureBlock {
|
||||
#[br(pad_before = 8)]
|
||||
num_blocks: u32,
|
||||
|
@ -103,7 +103,7 @@ struct TextureBlock {
|
|||
struct FileInfo {
|
||||
size: u32,
|
||||
file_type: FileType,
|
||||
file_size: i32,
|
||||
file_size: u32,
|
||||
|
||||
#[br(if (file_type == FileType::Standard))]
|
||||
standard_info: Option<StandardFileBlock>,
|
||||
|
@ -331,12 +331,15 @@ impl DatFile {
|
|||
let texture_file_info = file_info.texture_info.as_ref().unwrap();
|
||||
|
||||
// write the header if it exists
|
||||
if texture_file_info.lods[0].compressed_offset != 0 {
|
||||
let original_pos = self.file.stream_position().unwrap();
|
||||
let mipmap_size = texture_file_info.lods[0].compressed_size;
|
||||
if mipmap_size != 0 {
|
||||
let original_pos = self.file.stream_position().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];
|
||||
self.file.read(&mut header).ok()?;
|
||||
self.file.read_exact(&mut header).ok()?;
|
||||
|
||||
data.append(&mut header);
|
||||
|
||||
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);
|
||||
|
||||
for _ in 0..texture_file_info.lods[i as usize].block_count {
|
||||
data.append(&mut read_data_block(&self.file, running_block_total).unwrap());
|
||||
self.file.seek(SeekFrom::Start(running_block_total)).ok()?;
|
||||
running_block_total += i16::read(&mut self.file).unwrap() as u64;
|
||||
let original_pos = self.file.stream_position().ok()?;
|
||||
|
||||
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 crate::gamedata::MemoryBuffer;
|
||||
use binrw::BinRead;
|
||||
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)
|
||||
bitflags! {
|
||||
|
@ -35,51 +37,13 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[binread]
|
||||
struct TextureFormat : u32 {
|
||||
const TypeShift = 0xC;
|
||||
const TypeMask = 0xF000;
|
||||
const ComponentShift = 0x8;
|
||||
const ComponentMask = 0xF00;
|
||||
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]
|
||||
#[br(repr = u32)]
|
||||
#[derive(Debug)]
|
||||
enum TextureFormat {
|
||||
B8G8R8A8 = 0x1450,
|
||||
BC1 = 0x3420,
|
||||
BC5 = 0x3431
|
||||
}
|
||||
|
||||
#[binread]
|
||||
|
@ -98,7 +62,7 @@ struct TexHeader {
|
|||
}
|
||||
|
||||
pub struct Texture {
|
||||
|
||||
rgba: Vec<u8>
|
||||
}
|
||||
|
||||
impl Texture {
|
||||
|
@ -106,8 +70,38 @@ impl Texture {
|
|||
let mut cursor = Cursor::new(buffer);
|
||||
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