pen.rs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. use std::{
  2. fmt::Debug,
  3. fs::File,
  4. io::{Cursor, Read, Write},
  5. path::PathBuf,
  6. };
  7. use binrw::{BinRead, BinWrite, BinWriterExt, FilePtr64};
  8. use diff::Diff;
  9. use crate::{
  10. field_of::FieldOf,
  11. types::{Bool, Field, Rgba, WString, WobbleType, F64, U32},
  12. };
  13. #[derive(BinRead, Debug)]
  14. pub struct PenHeader {
  15. pub pen_count: u32,
  16. #[br(args {
  17. inner: binrw::args! {
  18. pen_count
  19. }
  20. })]
  21. pub data: FilePtr64<Pens>,
  22. }
  23. // Manually implement BinWrite as FilePtr does not support serialization
  24. // See: https://github.com/jam1garner/binrw/issues/4
  25. impl BinWrite for PenHeader {
  26. type Args<'a> = ();
  27. fn write_options<W: std::io::prelude::Write + std::io::prelude::Seek>(
  28. &self,
  29. writer: &mut W,
  30. endian: binrw::Endian,
  31. args: Self::Args<'_>,
  32. ) -> binrw::prelude::BinResult<()> {
  33. let pen_count: u32 = self.data.pens.len().try_into().unwrap();
  34. pen_count.write_options(writer, endian, args)?;
  35. // Write address of data, which is placed after this field
  36. let data_offset: u64 = writer.stream_position().unwrap() + 8;
  37. data_offset.write_options(writer, endian, args)?;
  38. self.data.pens.write_options(writer, endian, args)
  39. }
  40. }
  41. #[derive(BinRead, BinWrite, Debug, Diff, PartialEq)]
  42. #[diff(attr(
  43. #[derive(Debug, PartialEq)]
  44. ))]
  45. #[br(import {pen_count: u32})]
  46. pub struct Pens {
  47. #[br(count = pen_count)]
  48. pub pens: Vec<Pen>,
  49. }
  50. #[cfg_attr(feature = "default-debug", derive(Debug))]
  51. #[derive(BinRead, BinWrite, Clone, Diff, PartialEq)]
  52. #[diff(attr(
  53. #[derive(Debug, PartialEq)]
  54. ))]
  55. // #[brw(magic(236u32))] // Number of fields within this struct
  56. #[brw(magic(370u32))] // Number of fields within this struct
  57. pub struct Pen {
  58. pub color: FieldOf<Rgba>,
  59. pub name: WString,
  60. pub disabled: Bool,
  61. pub use_default: Bool,
  62. pub loop_count: U32,
  63. pub speed: F64, // Changes with wobble relative speed
  64. pub power: F64,
  65. pub frequency: U32,
  66. pub pulse_width: U32,
  67. pub start_tc: U32,
  68. pub end_tc: U32,
  69. pub polygon_tc: U32,
  70. pub jump_speed: F64,
  71. _unknown_2: [Field; 10],
  72. pub laser_off_tc: U32,
  73. pub wave: U32, // Only available if continue_mode is false
  74. pub pulse_width_2: F64,
  75. pub wobble_enable: U32,
  76. pub wobble_diameter: F64,
  77. pub wobble_distance: F64,
  78. _unknown_4: [Field; 8],
  79. pub min_jump_tc: U32,
  80. pub max_jump_tc: U32,
  81. pub jump_limit: F64,
  82. _unknown_5: [Field; 2],
  83. pub frequency_2: F64,
  84. _unknown_6: [Field; 152],
  85. pub wobble_type: FieldOf<WobbleType>,
  86. pub continue_mode: U32,
  87. _unknown_7: [Field; 12],
  88. pub wobble_diameter_2: F64, // Only with wobble type ellipse
  89. _unknown_8: [Field; 26],
  90. _unknown_9: [Field; 134],
  91. }
  92. impl Pen {
  93. pub fn read_from_file(path: &PathBuf) -> Self {
  94. let mut input: File = File::open(path).expect("Failed to open input file");
  95. let mut buffer: Cursor<Vec<u8>> = Cursor::new(vec![]);
  96. input
  97. .read_to_end(buffer.get_mut())
  98. .expect("Failed to read input file");
  99. Pen::read_le(&mut buffer).expect("Failed to deserialize input as object")
  100. }
  101. pub fn write_to_file(&self, path: &PathBuf) {
  102. let mut buffer: Cursor<Vec<u8>> = Cursor::new(vec![]);
  103. buffer.write_le(self).expect("Failed to serialize object");
  104. let mut output: File = File::create(path).expect("Failed to open output file");
  105. output
  106. .write_all(buffer.into_inner().as_slice())
  107. .expect("Failed to write to output file");
  108. }
  109. }
  110. // Custom Debug implementation to only print known fields
  111. #[cfg(not(feature = "default-debug"))]
  112. impl Debug for Pen {
  113. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  114. f.debug_struct("Pen")
  115. .field("color", &self.color)
  116. .field("name", &self.name)
  117. .field("disabled", &self.disabled)
  118. .field("use_default", &self.use_default)
  119. .field("loop_count", &self.loop_count)
  120. .field("speed", &self.speed)
  121. .field("power", &self.power)
  122. .field("frequency", &self.frequency)
  123. .field("start_tc", &self.start_tc)
  124. .field("end_tc", &self.end_tc)
  125. .field("polygon_tc", &self.polygon_tc)
  126. .field("jump_speed", &self.jump_speed)
  127. .field("laser_off_tc", &self.laser_off_tc)
  128. .field("wave", &self.wave)
  129. .field("wobble_enable", &self.wobble_enable)
  130. .field("wobble_diameter", &self.wobble_diameter)
  131. .field("wobble_distance", &self.wobble_distance)
  132. .field("min_jump_tc", &self.min_jump_tc)
  133. .field("max_jump_tc", &self.max_jump_tc)
  134. .field("jump_limit", &self.jump_limit)
  135. .field("frequency_2", &self.frequency_2)
  136. .field("wobble_type", &self.wobble_type)
  137. .field("continue_mode", &self.continue_mode)
  138. .field("wobble_diameter_2", &self.wobble_diameter_2)
  139. .finish()
  140. }
  141. }