1use std::io::{Cursor, Seek, SeekFrom};
5
6use crate::ByteSpan;
7use binrw::BinRead;
8use binrw::{BinReaderExt, binread, binrw};
9
10#[binrw]
11#[derive(Debug)]
12#[brw(little)]
13struct AvfxHeader {
14 name: u32,
15 size: u32,
16}
17
18#[binread]
19#[derive(Debug)]
20enum AvfxData {
21 #[brw(magic = b"XFVA")]
22 AvfxBase,
23 #[brw(magic = b"reV\0")]
24 Version,
25 #[brw(magic = b"PFDb")]
26 IsDelayFastParticle,
27 #[brw(magic = b"GFb\0")]
28 IsFitGround,
29 #[brw(magic = b"STb\0")]
30 IsTransformSkip,
31 #[brw(magic = b"HSAb")]
32 IsAllStopOnHide,
33 #[brw(magic = b"CBCb")]
34 CanBeClippedOut,
35 #[brw(magic = b"luCb")]
36 ClipBoxEnabled,
37 #[brw(magic = b"xPBC")]
38 ClipBoxX,
39 #[brw(magic = b"yPBC")]
40 ClipBoxY,
41 #[brw(magic = b"zPBC")]
42 ClipBoxZ,
43 #[brw(magic = b"xSBC")]
44 ClipBoxSizeX,
45 #[brw(magic = b"ySBC")]
46 ClipBoxSizeY,
47 #[brw(magic = b"zSBC")]
48 ClipBoxSizeZ,
49 #[brw(magic = b"sMBZ")]
50 BiasZmaxScale,
51 #[brw(magic = b"dMBZ")]
52 BiasZmaxDistance,
53 #[brw(magic = b"SmCb")]
54 IsCameraSpace,
55 #[brw(magic = b"LEFb")]
56 IsFullEnvLight,
57 #[brw(magic = b"tSOb")]
58 IsClipOwnSetting,
59 #[brw(magic = b"BCN\0")]
60 NearClipBegin,
61 #[brw(magic = b"ECN\0")]
62 NearClipEnd,
63 #[brw(magic = b"BCF\0")]
64 FarClipBegin,
65 #[brw(magic = b"ECF\0")]
66 FarClipEnd,
67 #[brw(magic = b"RFPS")]
68 SoftParticleFadeRange,
69 #[brw(magic = b"OKS\0")]
70 SoftKeyOffset,
71 #[brw(magic = b"yLwD")]
72 DrawLayerType,
73 #[brw(magic = b"TOwD")]
74 DrawOrderType,
75 #[brw(magic = b"TSLD")]
76 DirectionalLightSourceType,
77 #[brw(magic = b"S1LP")]
78 PointLightsType1,
79 #[brw(magic = b"S2LP")]
80 PointLightsType2,
81 #[brw(magic = b"xPvR")]
82 RevisedValuesPosX,
83 #[brw(magic = b"yPvR")]
84 RevisedValuesPosY,
85 #[brw(magic = b"zPvR")]
86 RevisedValuesPosZ,
87 #[brw(magic = b"xRvR")]
88 RevisedValuesRotX,
89 #[brw(magic = b"yRvR")]
90 RevisedValuesRotY,
91 #[brw(magic = b"zRvR")]
92 RevisedValuesRotZ,
93 #[brw(magic = b"xSvR")]
94 RevisedValuesScaleX,
95 #[brw(magic = b"ySvR")]
96 RevisedValuesScaleY,
97 #[brw(magic = b"zSvR")]
98 RevisedValuesScaleZ,
99 #[brw(magic = b"RvR\0")]
100 RevisedValuesColorR,
101 #[brw(magic = b"GvR\0")]
102 RevisedValuesColorG,
103 #[brw(magic = b"BvR\0")]
104 RevisedValuesColorB,
105 #[brw(magic = b"eXFA")]
106 FadeEnabledX,
107 #[brw(magic = b"iXFA")]
108 FadeInnerX,
109 #[brw(magic = b"oXFA")]
110 FadeOuterX,
111 #[brw(magic = b"eYFA")]
112 FadeEnabledY,
113 #[brw(magic = b"iYFA")]
114 FadeInnerY,
115 #[brw(magic = b"oYFA")]
116 FadeOuterY,
117 #[brw(magic = b"eZFA")]
118 FadeEnabledZ,
119 #[brw(magic = b"iZFA")]
120 FadeInnerZ,
121 #[brw(magic = b"oZFA")]
122 FadeOuterZ,
123 #[brw(magic = b"EFGb")]
124 GlobalFogEnabled,
125 #[brw(magic = b"MIFG")]
126 GlobalFogInfluence,
127 #[brw(magic = b"SGAb")]
128 AgsEnabled,
129 #[brw(magic = b"STLb")]
130 LtsEnabled,
131 #[brw(magic = b"nCcS")]
132 NumSchedulers,
133 #[brw(magic = b"nClT")]
134 NumTimelines,
135 #[brw(magic = b"nCmE")]
136 NumEmitters,
137 #[brw(magic = b"nCrP")]
138 NumParticles,
139 #[brw(magic = b"nCfE")]
140 NumEffectors,
141 #[brw(magic = b"nCdB")]
142 NumBinders,
143 #[brw(magic = b"nCxT")]
144 NumTextures,
145 #[brw(magic = b"nCdM")]
146 NumModels,
147 #[brw(magic = b"dhcS")]
148 Scheduler,
149 #[brw(magic = b"nLmT")]
150 Timeline,
151 #[brw(magic = b"timE")]
152 Emitter,
153 #[brw(magic = b"lctP")]
154 Particle,
155 #[brw(magic = b"tcfE")]
156 Effector,
157 #[brw(magic = b"dniB")]
158 Binder,
159 #[brw(magic = b"xeT\0")]
160 Texture,
161 #[brw(magic = b"ldoM")]
162 Model,
163}
164
165#[binread]
166#[derive(Debug)]
167#[brw(little)]
168struct AvfxBlock {
169 #[br(pad_before = 4)]
170 size: u32,
171
172 #[br(seek_before = SeekFrom::Current(-8))]
173 #[br(pad_after = 4)] data: AvfxData,
175}
176
177#[derive(Debug)]
178#[allow(dead_code)]
179pub struct Avfx {
180 clip_box: [f32; 3],
181 clip_box_size: [f32; 3],
182 revised_values_position: [f32; 3],
183 revised_values_rotation: [f32; 3],
184 revised_values_scale: [f32; 3],
185 revised_values_color: [f32; 3],
186
187 version: u32,
188 draw_layer_type: u32,
189 draw_order_type: u32,
190 directional_light_source_type: u32,
191 point_lights_type1: u32,
192 point_lights_type2: u32,
193
194 bias_z_max_scale: f32,
195 bias_z_max_distance: f32,
196 near_clip_begin: f32,
197 near_clip_end: f32,
198 fade_inner: [f32; 3],
199 fade_outer: [f32; 3],
200 far_clip_begin: f32,
201 far_clip_end: f32,
202 soft_particle_fade_range: f32,
203 soft_key_offset: f32,
204 global_fog_influence: f32,
205
206 is_delay_fast_particle: bool,
207 is_fit_ground: bool,
208 is_transform_skip: bool,
209 is_all_stop_on_hide: bool,
210 can_be_clipped_out: bool,
211 clip_box_enabled: bool,
212 is_camera_space: bool,
213 is_full_env_light: bool,
214 is_clip_own_setting: bool,
215 fade_enabled_x: bool,
216 fade_enabled_y: bool,
217 fade_enabled_z: bool,
218 global_fog_enabled: bool,
219 lts_enabled: bool,
220 ags_enabled: bool,
221
222 schedulers: Vec<AvfxBlock>,
223 timelines: Vec<AvfxBlock>,
224 emitters: Vec<AvfxBlock>,
225 particles: Vec<AvfxBlock>,
226 effectors: Vec<AvfxBlock>,
227 binders: Vec<AvfxBlock>,
228 textures: Vec<String>,
229 model: Vec<AvfxBlock>,
230}
231
232impl Default for Avfx {
233 fn default() -> Self {
234 Self {
235 clip_box: [0.0; 3],
236 clip_box_size: [0.0; 3],
237 revised_values_position: [0.0; 3],
238 revised_values_rotation: [0.0; 3],
239 revised_values_scale: [0.0; 3],
240 revised_values_color: [0.0; 3],
241 version: 0,
242 draw_layer_type: 0,
243 draw_order_type: 0,
244 directional_light_source_type: 0,
245 point_lights_type1: 0,
246 point_lights_type2: 0,
247 bias_z_max_scale: 0.0,
248 bias_z_max_distance: 0.0,
249 near_clip_begin: 0.0,
250 near_clip_end: 0.0,
251 fade_inner: [0.0; 3],
252 fade_outer: [0.0; 3],
253 far_clip_begin: 0.0,
254 far_clip_end: 0.0,
255 soft_particle_fade_range: 0.0,
256 soft_key_offset: 0.0,
257 global_fog_influence: 0.0,
258 is_delay_fast_particle: false,
259 is_fit_ground: false,
260 is_transform_skip: false,
261 is_all_stop_on_hide: false,
262 can_be_clipped_out: false,
263 clip_box_enabled: false,
264 is_camera_space: false,
265 is_full_env_light: false,
266 is_clip_own_setting: false,
267 fade_enabled_x: false,
268 fade_enabled_y: false,
269 fade_enabled_z: false,
270 global_fog_enabled: false,
271 lts_enabled: false,
272 ags_enabled: false,
273 schedulers: vec![],
274 timelines: vec![],
275 emitters: vec![],
276 particles: vec![],
277 effectors: vec![],
278 binders: vec![],
279 textures: vec![],
280 model: vec![],
281 }
282 }
283}
284
285impl Avfx {
286 pub fn from_existing(buffer: ByteSpan) -> Option<Self> {
288 let mut cursor = Cursor::new(buffer);
289 let header = AvfxHeader::read(&mut cursor).ok()?;
290
291 let mut avfx = Avfx::default();
292
293 let read_bool = |cursor: &mut Cursor<ByteSpan>| cursor.read_le::<u8>().unwrap() == 1u8;
294
295 let read_uint = |cursor: &mut Cursor<ByteSpan>| cursor.read_le::<u32>().unwrap();
296
297 let read_float = |cursor: &mut Cursor<ByteSpan>| cursor.read_le::<f32>().unwrap();
298
299 while cursor.position() < header.size as u64 {
300 let last_pos = cursor.position();
301 let block = AvfxBlock::read(&mut cursor).unwrap();
302 match block.data {
303 AvfxData::AvfxBase => {}
304 AvfxData::Version => {
305 avfx.version = read_uint(&mut cursor);
306 }
307 AvfxData::IsDelayFastParticle => {
308 avfx.is_delay_fast_particle = read_bool(&mut cursor);
309 }
310 AvfxData::IsFitGround => {
311 avfx.is_fit_ground = read_bool(&mut cursor);
312 }
313 AvfxData::IsTransformSkip => {
314 avfx.is_transform_skip = read_bool(&mut cursor);
315 }
316 AvfxData::IsAllStopOnHide => {
317 avfx.is_all_stop_on_hide = read_bool(&mut cursor);
318 }
319 AvfxData::CanBeClippedOut => {
320 avfx.can_be_clipped_out = read_bool(&mut cursor);
321 }
322 AvfxData::ClipBoxEnabled => {
323 avfx.clip_box_enabled = read_bool(&mut cursor);
324 }
325 AvfxData::ClipBoxX => {
326 avfx.clip_box[0] = read_float(&mut cursor);
327 }
328 AvfxData::ClipBoxY => {
329 avfx.clip_box[1] = read_float(&mut cursor);
330 }
331 AvfxData::ClipBoxZ => {
332 avfx.clip_box[2] = read_float(&mut cursor);
333 }
334 AvfxData::ClipBoxSizeX => {
335 avfx.clip_box_size[0] = read_float(&mut cursor);
336 }
337 AvfxData::ClipBoxSizeY => {
338 avfx.clip_box_size[1] = read_float(&mut cursor);
339 }
340 AvfxData::ClipBoxSizeZ => {
341 avfx.clip_box_size[2] = read_float(&mut cursor);
342 }
343 AvfxData::BiasZmaxScale => {
344 avfx.bias_z_max_scale = read_float(&mut cursor);
345 }
346 AvfxData::BiasZmaxDistance => {
347 avfx.bias_z_max_distance = read_float(&mut cursor);
348 }
349 AvfxData::IsCameraSpace => {
350 avfx.is_camera_space = read_bool(&mut cursor);
351 }
352 AvfxData::IsFullEnvLight => {
353 avfx.is_full_env_light = read_bool(&mut cursor);
354 }
355 AvfxData::IsClipOwnSetting => {
356 avfx.is_clip_own_setting = read_bool(&mut cursor);
357 }
358 AvfxData::NearClipBegin => {
359 avfx.near_clip_begin = read_float(&mut cursor);
360 }
361 AvfxData::NearClipEnd => {
362 avfx.near_clip_end = read_float(&mut cursor);
363 }
364 AvfxData::FarClipBegin => {
365 avfx.far_clip_begin = read_float(&mut cursor);
366 }
367 AvfxData::FarClipEnd => {
368 avfx.far_clip_end = read_float(&mut cursor);
369 }
370 AvfxData::SoftParticleFadeRange => {
371 avfx.soft_particle_fade_range = read_float(&mut cursor);
372 }
373 AvfxData::SoftKeyOffset => {
374 avfx.soft_key_offset = read_float(&mut cursor);
375 }
376 AvfxData::DrawLayerType => {
377 avfx.draw_layer_type = read_uint(&mut cursor);
378 }
379 AvfxData::DrawOrderType => {
380 avfx.draw_order_type = read_uint(&mut cursor);
381 }
382 AvfxData::DirectionalLightSourceType => {
383 avfx.directional_light_source_type = read_uint(&mut cursor);
384 }
385 AvfxData::PointLightsType1 => {
386 avfx.point_lights_type1 = read_uint(&mut cursor);
387 }
388 AvfxData::PointLightsType2 => {
389 avfx.point_lights_type2 = read_uint(&mut cursor);
390 }
391 AvfxData::RevisedValuesPosX => {
392 avfx.revised_values_position[0] = read_float(&mut cursor);
393 }
394 AvfxData::RevisedValuesPosY => {
395 avfx.revised_values_position[1] = read_float(&mut cursor);
396 }
397 AvfxData::RevisedValuesPosZ => {
398 avfx.revised_values_position[2] = read_float(&mut cursor);
399 }
400 AvfxData::RevisedValuesRotX => {
401 avfx.revised_values_rotation[0] = read_float(&mut cursor);
402 }
403 AvfxData::RevisedValuesRotY => {
404 avfx.revised_values_rotation[1] = read_float(&mut cursor);
405 }
406 AvfxData::RevisedValuesRotZ => {
407 avfx.revised_values_rotation[2] = read_float(&mut cursor);
408 }
409 AvfxData::RevisedValuesScaleX => {
410 avfx.revised_values_scale[0] = read_float(&mut cursor);
411 }
412 AvfxData::RevisedValuesScaleY => {
413 avfx.revised_values_scale[1] = read_float(&mut cursor);
414 }
415 AvfxData::RevisedValuesScaleZ => {
416 avfx.revised_values_scale[2] = read_float(&mut cursor);
417 }
418 AvfxData::RevisedValuesColorR => {
419 avfx.revised_values_color[0] = read_float(&mut cursor);
420 }
421 AvfxData::RevisedValuesColorG => {
422 avfx.revised_values_color[1] = read_float(&mut cursor);
423 }
424 AvfxData::RevisedValuesColorB => {
425 avfx.revised_values_color[2] = read_float(&mut cursor);
426 }
427 AvfxData::FadeEnabledX => {
428 avfx.fade_enabled_x = read_bool(&mut cursor);
429 }
430 AvfxData::FadeInnerX => {
431 avfx.fade_inner[0] = read_float(&mut cursor);
432 }
433 AvfxData::FadeOuterX => {
434 avfx.fade_outer[0] = read_float(&mut cursor);
435 }
436 AvfxData::FadeEnabledY => {
437 avfx.fade_enabled_y = read_bool(&mut cursor);
438 }
439 AvfxData::FadeInnerY => {
440 avfx.fade_inner[1] = read_float(&mut cursor);
441 }
442 AvfxData::FadeOuterY => {
443 avfx.fade_outer[1] = read_float(&mut cursor);
444 }
445 AvfxData::FadeEnabledZ => {
446 avfx.fade_enabled_z = read_bool(&mut cursor);
447 }
448 AvfxData::FadeInnerZ => {
449 avfx.fade_inner[2] = read_float(&mut cursor);
450 }
451 AvfxData::FadeOuterZ => {
452 avfx.fade_outer[2] = read_float(&mut cursor);
453 }
454 AvfxData::GlobalFogEnabled => {
455 avfx.global_fog_enabled = read_bool(&mut cursor);
456 }
457 AvfxData::GlobalFogInfluence => {
458 avfx.global_fog_influence = read_float(&mut cursor);
459 }
460 AvfxData::LtsEnabled => {
461 avfx.lts_enabled = read_bool(&mut cursor);
462 }
463 AvfxData::AgsEnabled => {
464 avfx.ags_enabled = read_bool(&mut cursor);
465 }
466 AvfxData::NumSchedulers => {
467 todo!()
468 }
469 AvfxData::NumTimelines => {
470 todo!()
471 }
472 AvfxData::NumEmitters => {
473 todo!()
474 }
475 AvfxData::NumParticles => {
476 todo!()
477 }
478 AvfxData::NumEffectors => {
479 todo!()
480 }
481 AvfxData::NumBinders => {
482 todo!()
483 }
484 AvfxData::NumTextures => {
485 todo!()
486 }
487 AvfxData::NumModels => {
488 todo!()
489 }
490 AvfxData::Scheduler => {
491 todo!()
492 }
493 AvfxData::Timeline => {
494 todo!()
495 }
496 AvfxData::Emitter => {
497 todo!()
498 }
499 AvfxData::Particle => {
500 todo!()
501 }
502 AvfxData::Effector => {
503 todo!()
504 }
505 AvfxData::Binder => {
506 todo!()
507 }
508 AvfxData::Texture => {
509 todo!()
510 }
511 AvfxData::Model => {
512 todo!()
513 }
514 }
515 let new_pos = cursor.position();
516 let read_bytes = (new_pos - last_pos) - 8;
517 let padding = block.size as u64 - read_bytes;
518 cursor.seek(SeekFrom::Current(padding as i64)).ok()?;
519 }
520
521 Some(avfx)
522 }
523}