espers 0.1.0

Library for reading ESP and ESM files
Documentation
use super::{get_cursor, Flags};
use crate::error::Error;
use crate::fields::{
    DecalData, ObjectBounds, DNAM, DODT, EDID, OBND, TX00, TX01, TX02, TX03, TX04, TX05, TX06, TX07,
};
use binrw::{binrw, BinRead};
use bitflags::bitflags;
use serde_derive::{Deserialize, Serialize};
use std::fmt;
use std::io::Cursor;

bitflags! {
    #[binrw]
    #[brw(little)]
    #[derive(Deserialize, Serialize)]
    pub struct TypeFlags: u16 {
        const NO_SPECULAR_MAP = 0x01;
        const FACEGEN_TEXTURES = 0x02;
        const MODEL_SPACE_NORMAL_MAP = 0x04;
    }
}

impl TryFrom<DNAM> for TypeFlags {
    type Error = Error;

    fn try_from(raw: DNAM) -> Result<Self, Self::Error> {
        let mut cursor = Cursor::new(&raw.data);
        Ok(Self::read(&mut cursor)?)
    }
}

#[binrw]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[brw(little, magic = b"TXST")]
pub struct TXST {
    pub size: u32,
    pub flags: Flags,
    pub form_id: u32,
    pub timestamp: u16,
    pub version_control: u16,
    pub internal_version: u16,
    pub unknown: u16,
    #[br(count = size)]
    pub data: Vec<u8>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TextureSet {
    pub edid: String,
    pub obnd: ObjectBounds,
    pub color_map: String,
    pub normal_map: Option<String>,
    pub mask: Option<String>,
    pub tone_map: Option<String>,
    pub detail_map: Option<String>,
    pub environment_map: Option<String>,
    pub multilayer: Option<String>,
    pub specularity_map: Option<String>,
    pub dodt: Option<DecalData>,
    pub flags: Option<TypeFlags>,
}

impl fmt::Display for TextureSet {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "TextureSet ({})", self.edid)
    }
}

impl TryFrom<TXST> for TextureSet {
    type Error = Error;

    fn try_from(raw: TXST) -> Result<Self, Self::Error> {
        let data = get_cursor(&raw.data, raw.flags.contains(Flags::COMPRESSED));
        let mut cursor = Cursor::new(&data);

        let edid = EDID::read(&mut cursor)?.try_into()?;
        let obnd = OBND::read(&mut cursor)?.try_into()?;
        let color_map = TX00::read(&mut cursor)?.try_into()?;
        let normal_map = TX01::read(&mut cursor)
            .ok()
            .map(TryInto::try_into)
            .transpose()?;
        let mask = TX02::read(&mut cursor)
            .ok()
            .map(TryInto::try_into)
            .transpose()?;
        let tone_map = TX03::read(&mut cursor)
            .ok()
            .map(TryInto::try_into)
            .transpose()?;
        let detail_map = TX04::read(&mut cursor)
            .ok()
            .map(TryInto::try_into)
            .transpose()?;
        let environment_map = TX05::read(&mut cursor)
            .ok()
            .map(TryInto::try_into)
            .transpose()?;
        let multilayer = TX06::read(&mut cursor)
            .ok()
            .map(TryInto::try_into)
            .transpose()?;
        let specularity_map = TX07::read(&mut cursor)
            .ok()
            .map(TryInto::try_into)
            .transpose()?;
        let dodt = DODT::read(&mut cursor)
            .ok()
            .map(TryInto::try_into)
            .transpose()?;
        let flags = DNAM::read(&mut cursor)
            .ok()
            .map(TryInto::try_into)
            .transpose()?;

        Ok(Self {
            edid,
            obnd,
            color_map,
            normal_map,
            mask,
            tone_map,
            detail_map,
            environment_map,
            multilayer,
            specularity_map,
            dodt,
            flags,
        })
    }
}