#![allow(unused)]
use std::collections::HashMap;
use std::io::{Cursor, SeekFrom};
use crate::common::Platform;
use crate::common_file_operations::Half3;
use crate::{ByteSpan, ReadableFile};
use binrw::{BinRead, BinResult, Endian};
use binrw::{BinReaderExt, binrw};
use half::f16;
const MAX_ELEMENTS: usize = 254;
#[binrw]
#[brw(import(num_colors: usize, num_scalars: usize))]
#[derive(Debug)]
#[allow(dead_code)]
struct StainingTemplateEntry {
#[br(map = calc_byte_counts, count = num_colors + num_scalars)]
byte_counts: Vec<u16>,
#[br(parse_with = read_color_array, args(&byte_counts, num_colors))]
#[bw(ignore)]
colors: Vec<Half3>,
#[br(parse_with = read_scalar_array, args(&byte_counts, num_colors, num_scalars))]
#[bw(ignore)]
scalars: Vec<u16>,
}
#[derive(Debug)]
pub struct LegacyDye {
pub diffuse: [f32; 3],
pub specular: [f32; 3],
pub emissive: [f32; 3],
pub shininess: f32,
pub specular_mask: f32,
}
impl From<StainingTemplateEntry> for LegacyDye {
fn from(value: StainingTemplateEntry) -> Self {
Self {
diffuse: value.colors[0].into(),
specular: value.colors[1].into(),
emissive: value.colors[2].into(),
shininess: f16::from_bits(value.scalars[0]).to_f32_const(),
specular_mask: f16::from_bits(value.scalars[1]).to_f32_const(),
}
}
}
#[derive(Debug)]
pub struct Dye {
pub diffuse: [f32; 3],
pub specular: [f32; 3],
pub emissive: [f32; 3],
scalar3: f32, pub metalness: f32,
pub roughness: f32,
pub sheen_rate: f32,
pub sheen_tint_rate: f32,
pub sheen_aperture: f32,
pub anisotropy: f32,
pub raw_sphere_map_index: u16,
pub sphere_map_mask: f32,
}
impl From<StainingTemplateEntry> for Dye {
fn from(value: StainingTemplateEntry) -> Self {
Self {
diffuse: value.colors[0].into(),
specular: value.colors[1].into(),
emissive: value.colors[2].into(),
scalar3: f16::from_bits(value.scalars[9]).to_f32_const(),
metalness: f16::from_bits(value.scalars[1]).to_f32_const(),
roughness: f16::from_bits(value.scalars[2]).to_f32_const(),
sheen_rate: f16::from_bits(value.scalars[3]).to_f32_const(),
sheen_tint_rate: f16::from_bits(value.scalars[4]).to_f32_const(),
sheen_aperture: f16::from_bits(value.scalars[5]).to_f32_const(),
anisotropy: f16::from_bits(value.scalars[6]).to_f32_const(),
raw_sphere_map_index: value.scalars[7],
sphere_map_mask: f16::from_bits(value.scalars[8]).to_f32_const(),
}
}
}
fn calc_byte_counts(ends: Vec<u16>) -> Vec<u16> {
let mut last_end = 0;
let mut byte_counts = Vec::new();
for end in ends {
let next_end = end * 2;
byte_counts.push(next_end.wrapping_sub(last_end));
last_end = next_end;
}
byte_counts
}
#[binrw::parser(reader, endian)]
fn read_color_array(byte_counts: &[u16], num_colors: usize) -> BinResult<Vec<Half3>> {
let mut entries = Vec::with_capacity(num_colors);
for count in byte_counts.iter().take(num_colors) {
let mut array: Vec<Half3> = read_array(reader, endian, *count);
entries.append(&mut array); }
Ok(entries)
}
#[binrw::parser(reader, endian)]
fn read_scalar_array(
byte_counts: &[u16],
num_colors: usize,
num_scalars: usize,
) -> BinResult<Vec<u16>> {
let mut entries = Vec::with_capacity(num_scalars);
for count in byte_counts.iter().skip(num_colors).take(num_scalars) {
let mut array: Vec<u16> = read_array(reader, endian, *count);
entries.append(&mut array); }
Ok(entries)
}
fn read_array<
T: binrw::BinRead<Args<'static> = ()> + Default + Clone + Copy,
R: std::io::Read + BinReaderExt,
>(
cursor: &mut R,
endian: Endian,
size: u16,
) -> Vec<T> {
let array_size = size as usize / std::mem::size_of::<T>();
if array_size == 0 {
vec![T::default(); MAX_ELEMENTS]
} else if array_size == 1 {
let element = cursor.read_type::<T>(endian).unwrap();
vec![element; MAX_ELEMENTS]
} else if array_size < MAX_ELEMENTS {
let real_count = (size as usize - MAX_ELEMENTS) / std::mem::size_of::<T>();
let mut values = vec![];
let mut indices = vec![];
values.push(T::default());
for _ in 0..real_count {
values.push(cursor.read_type::<T>(endian).unwrap());
}
let eof_marker = cursor.read_type::<u8>(endian).unwrap();
assert_eq!(eof_marker, 0xFF);
for _ in 0..MAX_ELEMENTS - 1 {
indices.push(cursor.read_type::<u8>(endian).unwrap());
}
let mut vec = vec![];
for index in indices {
if (index as usize) < values.len() {
vec.push(values[index as usize]);
} else {
vec.push(T::default());
}
}
vec
} else if array_size == MAX_ELEMENTS {
let mut vec = vec![];
for _ in 0..size {
vec.push(cursor.read_type::<T>(endian).unwrap());
}
vec
} else {
panic!("Too many elements");
}
}
#[binrw]
#[derive(Debug)]
#[brw(magic = 0x534Du16)]
pub struct Stm {
version: u16,
entry_count: u16,
unk1: u16,
#[br(count = entry_count)]
keys: Vec<u32>,
#[br(count = entry_count)]
offsets: Vec<u32>,
#[br(calc = 3)]
#[bw(ignore)]
num_colors: usize,
#[br(calc = if version == 0x101 { 2 } else { 9 } )]
#[bw(ignore)]
num_scalars: usize,
#[br(if(version != 0x101), parse_with = read_entries, args(&keys, &offsets, num_colors, num_scalars))]
#[bw(ignore)] pub dyes: HashMap<u32, Dye>,
#[br(if(version == 0x101), parse_with = read_entries, args(&keys, &offsets, num_colors, num_scalars))]
#[bw(ignore)] pub legacy_dyes: HashMap<u32, LegacyDye>,
}
#[binrw::parser(reader, endian)]
fn read_entries<T: From<StainingTemplateEntry>>(
keys: &[u32],
offsets: &[u32],
num_colors: usize,
num_scalars: usize,
) -> BinResult<HashMap<u32, T>> {
let mut entries = HashMap::with_capacity(keys.len());
let start_position = reader.stream_position().unwrap();
for (key, offset) in keys.iter().zip(offsets) {
reader.seek(SeekFrom::Start(start_position + *offset as u64 * 2))?;
let entry: StainingTemplateEntry =
reader.read_type_args(endian, (num_colors, num_scalars))?;
entries.insert(*key, T::from(entry));
}
Ok(entries)
}
impl ReadableFile for Stm {
fn from_existing(platform: Platform, buffer: ByteSpan) -> Option<Self> {
let mut cursor = Cursor::new(buffer);
Stm::read_options(&mut cursor, platform.endianness(), ()).ok()
}
}
#[cfg(test)]
mod tests {
use crate::pass_random_invalid;
use super::*;
#[test]
fn test_invalid() {
pass_random_invalid::<Stm>();
}
}