diff --git a/src/avfx.rs b/src/avfx.rs index 21961d4..a2d742e 100644 --- a/src/avfx.rs +++ b/src/avfx.rs @@ -1,11 +1,13 @@ // SPDX-FileCopyrightText: 2024 Joshua Goins // SPDX-License-Identifier: GPL-3.0-or-later -use std::io::Cursor; +use std::io::{Cursor, Seek, SeekFrom}; +use std::ptr::read; use crate::ByteSpan; -use binrw::binrw; +use binrw::{binread, BinReaderExt, binrw}; use binrw::BinRead; +use crate::dat::Block; #[binrw] #[derive(Debug)] @@ -15,17 +17,514 @@ struct AvfxHeader { size: u32 } +#[binread] +#[derive(Debug)] +enum AvfxData { + #[brw(magic = b"XFVA")] + AvfxBase, + #[brw(magic = b"reV\0")] + Version, + #[brw(magic = b"PFDb")] + IsDelayFastParticle, + #[brw(magic = b"GFb\0")] + IsFitGround, + #[brw(magic = b"STb\0")] + IsTransformSkip, + #[brw(magic = b"HSAb")] + IsAllStopOnHide, + #[brw(magic = b"CBCb")] + CanBeClippedOut, + #[brw(magic = b"luCb")] + ClipBoxEnabled, + #[brw(magic = b"xPBC")] + ClipBoxX, + #[brw(magic = b"yPBC")] + ClipBoxY, + #[brw(magic = b"zPBC")] + ClipBoxZ, + #[brw(magic = b"xSBC")] + ClipBoxSizeX, + #[brw(magic = b"ySBC")] + ClipBoxSizeY, + #[brw(magic = b"zSBC")] + ClipBoxSizeZ, + #[brw(magic = b"sMBZ")] + BiasZmaxScale, + #[brw(magic = b"dMBZ")] + BiasZmaxDistance, + #[brw(magic = b"SmCb")] + IsCameraSpace, + #[brw(magic = b"LEFb")] + IsFullEnvLight, + #[brw(magic = b"tSOb")] + IsClipOwnSetting, + #[brw(magic = b"BCN\0")] + NearClipBegin, + #[brw(magic = b"ECN\0")] + NearClipEnd, + #[brw(magic = b"BCF\0")] + FarClipBegin, + #[brw(magic = b"ECF\0")] + FarClipEnd, + #[brw(magic = b"RFPS")] + SoftParticleFadeRange, + #[brw(magic = b"OKS\0")] + SoftKeyOffset, + #[brw(magic = b"yLwD")] + DrawLayerType, + #[brw(magic = b"TOwD")] + DrawOrderType, + #[brw(magic = b"TSLD")] + DirectionalLightSourceType, + #[brw(magic = b"S1LP")] + PointLightsType1, + #[brw(magic = b"S2LP")] + PointLightsType2, + #[brw(magic = b"xPvR")] + RevisedValuesPosX, + #[brw(magic = b"yPvR")] + RevisedValuesPosY, + #[brw(magic = b"zPvR")] + RevisedValuesPosZ, + #[brw(magic = b"xRvR")] + RevisedValuesRotX, + #[brw(magic = b"yRvR")] + RevisedValuesRotY, + #[brw(magic = b"zRvR")] + RevisedValuesRotZ, + #[brw(magic = b"xSvR")] + RevisedValuesScaleX, + #[brw(magic = b"ySvR")] + RevisedValuesScaleY, + #[brw(magic = b"zSvR")] + RevisedValuesScaleZ, + #[brw(magic = b"RvR\0")] + RevisedValuesColorR, + #[brw(magic = b"GvR\0")] + RevisedValuesColorG, + #[brw(magic = b"BvR\0")] + RevisedValuesColorB, + #[brw(magic = b"eXFA")] + FadeEnabledX, + #[brw(magic = b"iXFA")] + FadeInnerX, + #[brw(magic = b"oXFA")] + FadeOuterX, + #[brw(magic = b"eYFA")] + FadeEnabledY, + #[brw(magic = b"iYFA")] + FadeInnerY, + #[brw(magic = b"oYFA")] + FadeOuterY, + #[brw(magic = b"eZFA")] + FadeEnabledZ, + #[brw(magic = b"iZFA")] + FadeInnerZ, + #[brw(magic = b"oZFA")] + FadeOuterZ, + #[brw(magic = b"EFGb")] + GlobalFogEnabled, + #[brw(magic = b"MIFG")] + GlobalFogInfluence, + #[brw(magic = b"SGAb")] + AgsEnabled, + #[brw(magic = b"STLb")] + LtsEnabled, + #[brw(magic = b"nCcS")] + NumSchedulers, + #[brw(magic = b"nClT")] + NumTimelines, + #[brw(magic = b"nCmE")] + NumEmitters, + #[brw(magic = b"nCrP")] + NumParticles, + #[brw(magic = b"nCfE")] + NumEffectors, + #[brw(magic = b"nCdB")] + NumBinders, + #[brw(magic = b"nCxT")] + NumTextures, + #[brw(magic = b"nCdM")] + NumModels, + #[brw(magic = b"dhcS")] + Scheduler, + #[brw(magic = b"nLmT")] + Timeline, + #[brw(magic = b"timE")] + Emitter, + #[brw(magic = b"lctP")] + Particle, + #[brw(magic = b"tcfE")] + Effector, + #[brw(magic = b"dniB")] + Binder, + #[brw(magic = b"xeT\0")] + Texture, + #[brw(magic = b"ldoM")] + Model, +} + +#[binread] +#[derive(Debug)] +#[brw(little)] +struct AvfxBlock { + #[br(pad_before = 4)] + size: u32, + + #[br(seek_before = SeekFrom::Current(-8))] + #[br(pad_after = 4)] // skip over size + data: AvfxData, +} + #[derive(Debug)] pub struct Avfx { + clip_box: [f32; 3], + clip_box_size: [f32; 3], + revised_values_position: [f32; 3], + revised_values_rotation: [f32; 3], + revised_values_scale: [f32; 3], + revised_values_color: [f32; 3], + version: u32, + draw_layer_type: u32, + draw_order_type: u32, + directional_light_source_type: u32, + point_lights_type1: u32, + point_lights_type2: u32, + + bias_z_max_scale: f32, + bias_z_max_distance: f32, + near_clip_begin: f32, + near_clip_end: f32, + fade_inner: [f32; 3], + fade_outer: [f32; 3], + far_clip_begin: f32, + far_clip_end: f32, + soft_particle_fade_range: f32, + soft_key_offset: f32, + global_fog_influence: f32, + + is_delay_fast_particle: bool, + is_fit_ground: bool, + is_transform_skip: bool, + is_all_stop_on_hide: bool, + can_be_clipped_out: bool, + clip_box_enabled: bool, + is_camera_space: bool, + is_full_env_light: bool, + is_clip_own_setting: bool, + fade_enabled_x: bool, + fade_enabled_y: bool, + fade_enabled_z: bool, + global_fog_enabled: bool, + lts_enabled: bool, + ags_enabled: bool, + + schedulers: Vec, + timelines: Vec, + emitters: Vec, + particles: Vec, + effectors: Vec, + binders: Vec, + textures: Vec, + model: Vec, +} + +impl Default for Avfx { + fn default() -> Self { + Self { + clip_box: [0.0; 3], + clip_box_size: [0.0; 3], + revised_values_position: [0.0; 3], + revised_values_rotation: [0.0; 3], + revised_values_scale: [0.0; 3], + revised_values_color: [0.0; 3], + version: 0, + draw_layer_type: 0, + draw_order_type: 0, + directional_light_source_type: 0, + point_lights_type1: 0, + point_lights_type2: 0, + bias_z_max_scale: 0.0, + bias_z_max_distance: 0.0, + near_clip_begin: 0.0, + near_clip_end: 0.0, + fade_inner: [0.0; 3], + fade_outer: [0.0; 3], + far_clip_begin: 0.0, + far_clip_end: 0.0, + soft_particle_fade_range: 0.0, + soft_key_offset: 0.0, + global_fog_influence: 0.0, + is_delay_fast_particle: false, + is_fit_ground: false, + is_transform_skip: false, + is_all_stop_on_hide: false, + can_be_clipped_out: false, + clip_box_enabled: false, + is_camera_space: false, + is_full_env_light: false, + is_clip_own_setting: false, + fade_enabled_x: false, + fade_enabled_y: false, + fade_enabled_z: false, + global_fog_enabled: false, + lts_enabled: false, + ags_enabled: false, + schedulers: vec![], + timelines: vec![], + emitters: vec![], + particles: vec![], + effectors: vec![], + binders: vec![], + textures: vec![], + model: vec![], + } + } } impl Avfx { - /// Reads an existing ULD file + /// Reads an existing Avfx file pub fn from_existing(buffer: ByteSpan) -> Option { let mut cursor = Cursor::new(buffer); let header = AvfxHeader::read(&mut cursor).ok()?; - Some(Avfx{}) + let mut avfx = Avfx::default(); + + let read_bool = |cursor: &mut Cursor| { + return cursor.read_le::().unwrap() == 1u8; + }; + + let read_uint = |cursor: &mut Cursor| { + return cursor.read_le::().unwrap(); + }; + + let read_float = |cursor: &mut Cursor| { + return cursor.read_le::().unwrap(); + }; + + while cursor.position() < header.size as u64 { + let last_pos = cursor.position(); + let block = AvfxBlock::read(&mut cursor).unwrap(); + match block.data { + AvfxData::AvfxBase => {} + AvfxData::Version => { + avfx.version = read_uint(&mut cursor); + } + AvfxData::IsDelayFastParticle => { + avfx.is_delay_fast_particle = read_bool(&mut cursor); + } + AvfxData::IsFitGround => { + avfx.is_fit_ground = read_bool(&mut cursor); + } + AvfxData::IsTransformSkip => { + avfx.is_transform_skip = read_bool(&mut cursor); + } + AvfxData::IsAllStopOnHide => { + avfx.is_all_stop_on_hide = read_bool(&mut cursor); + } + AvfxData::CanBeClippedOut => { + avfx.can_be_clipped_out = read_bool(&mut cursor); + } + AvfxData::ClipBoxEnabled => { + avfx.clip_box_enabled = read_bool(&mut cursor); + } + AvfxData::ClipBoxX => { + avfx.clip_box[0] = read_float(&mut cursor); + } + AvfxData::ClipBoxY => { + avfx.clip_box[1] = read_float(&mut cursor); + } + AvfxData::ClipBoxZ => { + avfx.clip_box[2] = read_float(&mut cursor); + } + AvfxData::ClipBoxSizeX => { + avfx.clip_box_size[0] = read_float(&mut cursor); + } + AvfxData::ClipBoxSizeY => { + avfx.clip_box_size[1] = read_float(&mut cursor); + } + AvfxData::ClipBoxSizeZ => { + avfx.clip_box_size[2] = read_float(&mut cursor); + } + AvfxData::BiasZmaxScale => { + avfx.bias_z_max_scale = read_float(&mut cursor); + } + AvfxData::BiasZmaxDistance => { + avfx.bias_z_max_distance = read_float(&mut cursor); + } + AvfxData::IsCameraSpace => { + avfx.is_camera_space = read_bool(&mut cursor); + } + AvfxData::IsFullEnvLight => { + avfx.is_full_env_light = read_bool(&mut cursor); + } + AvfxData::IsClipOwnSetting => { + avfx.is_clip_own_setting = read_bool(&mut cursor); + } + AvfxData::NearClipBegin => { + avfx.near_clip_begin = read_float(&mut cursor); + } + AvfxData::NearClipEnd => { + avfx.near_clip_end = read_float(&mut cursor); + } + AvfxData::FarClipBegin => { + avfx.far_clip_begin = read_float(&mut cursor); + } + AvfxData::FarClipEnd => { + avfx.far_clip_end = read_float(&mut cursor); + } + AvfxData::SoftParticleFadeRange => { + avfx.soft_particle_fade_range = read_float(&mut cursor); + } + AvfxData::SoftKeyOffset => { + avfx.soft_key_offset = read_float(&mut cursor); + } + AvfxData::DrawLayerType => { + avfx.draw_layer_type = read_uint(&mut cursor); + } + AvfxData::DrawOrderType => { + avfx.draw_order_type = read_uint(&mut cursor); + } + AvfxData::DirectionalLightSourceType => { + avfx.directional_light_source_type = read_uint(&mut cursor); + } + AvfxData::PointLightsType1 => { + avfx.point_lights_type1 = read_uint(&mut cursor); + } + AvfxData::PointLightsType2 => { + avfx.point_lights_type2 = read_uint(&mut cursor); + } + AvfxData::RevisedValuesPosX => { + avfx.revised_values_position[0] = read_float(&mut cursor); + } + AvfxData::RevisedValuesPosY => { + avfx.revised_values_position[1] = read_float(&mut cursor); + } + AvfxData::RevisedValuesPosZ => { + avfx.revised_values_position[2] = read_float(&mut cursor); + } + AvfxData::RevisedValuesRotX => { + avfx.revised_values_rotation[0] = read_float(&mut cursor); + } + AvfxData::RevisedValuesRotY => { + avfx.revised_values_rotation[1] = read_float(&mut cursor); + } + AvfxData::RevisedValuesRotZ => { + avfx.revised_values_rotation[2] = read_float(&mut cursor); + } + AvfxData::RevisedValuesScaleX => { + avfx.revised_values_scale[0] = read_float(&mut cursor); + } + AvfxData::RevisedValuesScaleY => { + avfx.revised_values_scale[1] = read_float(&mut cursor); + } + AvfxData::RevisedValuesScaleZ => { + avfx.revised_values_scale[2] = read_float(&mut cursor); + } + AvfxData::RevisedValuesColorR => { + avfx.revised_values_color[0] = read_float(&mut cursor); + } + AvfxData::RevisedValuesColorG => { + avfx.revised_values_color[1] = read_float(&mut cursor); + } + AvfxData::RevisedValuesColorB => { + avfx.revised_values_color[2] = read_float(&mut cursor); + } + AvfxData::FadeEnabledX => { + avfx.fade_enabled_x = read_bool(&mut cursor); + } + AvfxData::FadeInnerX => { + avfx.fade_inner[0] = read_float(&mut cursor); + } + AvfxData::FadeOuterX => { + avfx.fade_outer[0] = read_float(&mut cursor); + } + AvfxData::FadeEnabledY => { + avfx.fade_enabled_y = read_bool(&mut cursor); + } + AvfxData::FadeInnerY => { + avfx.fade_inner[1] = read_float(&mut cursor); + } + AvfxData::FadeOuterY => { + avfx.fade_outer[1] = read_float(&mut cursor); + } + AvfxData::FadeEnabledZ => { + avfx.fade_enabled_z = read_bool(&mut cursor); + } + AvfxData::FadeInnerZ => { + avfx.fade_inner[2] = read_float(&mut cursor); + } + AvfxData::FadeOuterZ => { + avfx.fade_outer[2] = read_float(&mut cursor); + } + AvfxData::GlobalFogEnabled => { + avfx.global_fog_enabled = read_bool(&mut cursor); + } + AvfxData::GlobalFogInfluence => { + avfx.global_fog_influence = read_float(&mut cursor); + } + AvfxData::LtsEnabled => { + avfx.lts_enabled = read_bool(&mut cursor); + } + AvfxData::AgsEnabled => { + avfx.ags_enabled = read_bool(&mut cursor); + } + AvfxData::NumSchedulers => { + todo!() + } + AvfxData::NumTimelines => { + todo!() + } + AvfxData::NumEmitters => { + todo!() + } + AvfxData::NumParticles => { + todo!() + } + AvfxData::NumEffectors => { + todo!() + } + AvfxData::NumBinders => { + todo!() + } + AvfxData::NumTextures => { + todo!() + } + AvfxData::NumModels => { + todo!() + } + AvfxData::Scheduler => { + todo!() + } + AvfxData::Timeline => { + todo!() + } + AvfxData::Emitter => { + todo!() + } + AvfxData::Particle => { + todo!() + } + AvfxData::Effector => { + todo!() + } + AvfxData::Binder => { + todo!() + } + AvfxData::Texture => { + todo!() + } + AvfxData::Model => { + todo!() + } + } + let new_pos = cursor.position(); + let read_bytes = (new_pos - last_pos) - 8; + let padding = block.size as u64 - read_bytes; + cursor.seek(SeekFrom::Current(padding as i64)); + } + + Some(avfx) } }