pen.rs 6.5 KB

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