123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- use std::{
- fmt::Debug,
- fs::File,
- io::{Cursor, Read, Write},
- path::PathBuf,
- };
- use binrw::{BinRead, BinWrite, BinWriterExt, FilePtr64};
- use diff::Diff;
- use crate::{
- field_of::FieldOf,
- types::{Bool, Field, Rgba, WString, WobbleType, F64, U32},
- };
- #[derive(BinRead, Debug)]
- pub struct PenHeader {
- pub pen_count: u32,
- #[br(args {
- inner: binrw::args! {
- pen_count
- }
- })]
- pub data: FilePtr64<Pens>,
- }
- // Manually implement BinWrite as FilePtr does not support serialization
- // See: https://github.com/jam1garner/binrw/issues/4
- impl BinWrite for PenHeader {
- type Args<'a> = ();
- fn write_options<W: std::io::prelude::Write + std::io::prelude::Seek>(
- &self,
- writer: &mut W,
- endian: binrw::Endian,
- args: Self::Args<'_>,
- ) -> binrw::prelude::BinResult<()> {
- let pen_count: u32 = self.data.pens.len().try_into().unwrap();
- pen_count.write_options(writer, endian, args)?;
- // Write address of data, which is placed after this field
- let data_offset: u64 = writer.stream_position().unwrap() + 8;
- data_offset.write_options(writer, endian, args)?;
- self.data.pens.write_options(writer, endian, args)
- }
- }
- #[derive(BinRead, BinWrite, Debug, Diff, PartialEq)]
- #[diff(attr(
- #[derive(Debug, PartialEq)]
- ))]
- #[br(import {pen_count: u32})]
- pub struct Pens {
- #[br(count = pen_count)]
- pub pens: Vec<Pen>,
- }
- #[cfg_attr(feature = "default-debug", derive(Debug))]
- #[derive(BinRead, BinWrite, Clone, Diff, PartialEq)]
- #[diff(attr(
- #[derive(Debug, PartialEq)]
- ))]
- // #[brw(magic(236u32))] // Number of fields within this struct
- #[brw(magic(370u32))] // Number of fields within this struct
- pub struct Pen {
- pub color: FieldOf<Rgba>,
- pub name: WString,
- pub disabled: Bool,
- pub use_default: Bool,
- pub loop_count: U32,
- pub speed: F64, // Changes with wobble relative speed
- pub power: F64,
- pub frequency: U32,
- pub pulse_width: U32,
- pub start_tc: U32,
- pub end_tc: U32,
- pub polygon_tc: U32,
- pub jump_speed: F64,
- _unknown_2: [Field; 10],
- pub laser_off_tc: U32,
- pub wave: U32, // Only available if continue_mode is false
- pub pulse_width_2: F64,
- pub wobble_enable: U32,
- pub wobble_diameter: F64,
- pub wobble_distance: F64,
- _unknown_4: [Field; 8],
- pub min_jump_tc: U32,
- pub max_jump_tc: U32,
- pub jump_limit: F64,
- _unknown_5: [Field; 2],
- pub frequency_2: F64,
- _unknown_6: [Field; 152],
- pub wobble_type: FieldOf<WobbleType>,
- pub continue_mode: U32,
- _unknown_7: [Field; 12],
- pub wobble_diameter_2: F64, // Only with wobble type ellipse
- _unknown_8: [Field; 26],
- _unknown_9: [Field; 134],
- }
- impl Pen {
- pub fn read_from_file(path: &PathBuf) -> Self {
- let mut input: File = File::open(path).expect("Failed to open input file");
- let mut buffer: Cursor<Vec<u8>> = Cursor::new(vec![]);
- input
- .read_to_end(buffer.get_mut())
- .expect("Failed to read input file");
- Pen::read_le(&mut buffer).expect("Failed to deserialize input as object")
- }
- pub fn write_to_file(&self, path: &PathBuf) {
- let mut buffer: Cursor<Vec<u8>> = Cursor::new(vec![]);
- buffer.write_le(self).expect("Failed to serialize object");
- let mut output: File = File::create(path).expect("Failed to open output file");
- output
- .write_all(buffer.into_inner().as_slice())
- .expect("Failed to write to output file");
- }
- }
- // Custom Debug implementation to only print known fields
- #[cfg(not(feature = "default-debug"))]
- impl Debug for Pen {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("Pen")
- .field("color", &self.color)
- .field("name", &self.name)
- .field("disabled", &self.disabled)
- .field("use_default", &self.use_default)
- .field("loop_count", &self.loop_count)
- .field("speed", &self.speed)
- .field("power", &self.power)
- .field("frequency", &self.frequency)
- .field("start_tc", &self.start_tc)
- .field("end_tc", &self.end_tc)
- .field("polygon_tc", &self.polygon_tc)
- .field("jump_speed", &self.jump_speed)
- .field("laser_off_tc", &self.laser_off_tc)
- .field("wave", &self.wave)
- .field("wobble_enable", &self.wobble_enable)
- .field("wobble_diameter", &self.wobble_diameter)
- .field("wobble_distance", &self.wobble_distance)
- .field("min_jump_tc", &self.min_jump_tc)
- .field("max_jump_tc", &self.max_jump_tc)
- .field("jump_limit", &self.jump_limit)
- .field("frequency_2", &self.frequency_2)
- .field("wobble_type", &self.wobble_type)
- .field("continue_mode", &self.continue_mode)
- .field("wobble_diameter_2", &self.wobble_diameter_2)
- .finish()
- }
- }
|