|
@@ -7,6 +7,8 @@ use std::{
|
|
|
|
|
|
use binrw::{BinRead, BinWrite, BinWriterExt};
|
|
use binrw::{BinRead, BinWrite, BinWriterExt};
|
|
use diff::Diff;
|
|
use diff::Diff;
|
|
|
|
+use itertools::Itertools;
|
|
|
|
+use log::debug;
|
|
use modular_bitfield::{
|
|
use modular_bitfield::{
|
|
bitfield,
|
|
bitfield,
|
|
specifiers::{B1, B14},
|
|
specifiers::{B1, B14},
|
|
@@ -305,10 +307,113 @@ impl ObjectModifier {
|
|
|
|
|
|
pub fn skew(&self) -> Coordinate {
|
|
pub fn skew(&self) -> Coordinate {
|
|
Coordinate {
|
|
Coordinate {
|
|
- x: self.modifiers.x_skew,
|
|
|
|
- y: self.modifiers.y_skew,
|
|
|
|
|
|
+ x: self.modifiers.y_skew.asin(), // Radians from X axis
|
|
|
|
+ y: self.modifiers.x_skew.asin(), // Radians from Y axis
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /// Returns origin, width, and height of bounding box given two rectangular corners
|
|
|
|
+ pub fn corrected(&self, pt1: Coordinate, pt2: Coordinate) -> (Coordinate, f64, f64) {
|
|
|
|
+ debug!(
|
|
|
|
+ "Skew degree from X axis: {:.2}",
|
|
|
|
+ self.modifiers.x_skew.asin().to_degrees()
|
|
|
|
+ );
|
|
|
|
+ debug!(
|
|
|
|
+ "Skew degree from Y axis: {:.2}",
|
|
|
|
+ self.modifiers.y_skew.asin().to_degrees()
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ // // Calculated unskewed width and height
|
|
|
|
+ // let Coordinate {
|
|
|
|
+ // x: width,
|
|
|
|
+ // y: height,
|
|
|
|
+ // } = (pt1.max(pt2) - pt1.min(pt2)) * self.scale();
|
|
|
|
+
|
|
|
|
+ // debug!("Drawn point 1: {}", pt1);
|
|
|
|
+ // debug!("Drawn point 2: {}", pt2);
|
|
|
|
+
|
|
|
|
+ // Calculate all 4 points of drawn rectangle
|
|
|
|
+ let points: Vec<Coordinate> = vec![
|
|
|
|
+ Coordinate {
|
|
|
|
+ x: pt1.min(pt2).x,
|
|
|
|
+ y: pt1.min(pt2).y,
|
|
|
|
+ },
|
|
|
|
+ Coordinate {
|
|
|
|
+ x: pt1.min(pt2).x,
|
|
|
|
+ y: pt1.max(pt2).y,
|
|
|
|
+ },
|
|
|
|
+ Coordinate {
|
|
|
|
+ x: pt1.max(pt2).x,
|
|
|
|
+ y: pt1.max(pt2).y,
|
|
|
|
+ },
|
|
|
|
+ Coordinate {
|
|
|
|
+ x: pt1.max(pt2).x,
|
|
|
|
+ y: pt1.min(pt2).y,
|
|
|
|
+ },
|
|
|
|
+ ];
|
|
|
|
+
|
|
|
|
+ debug!(
|
|
|
|
+ "Drawn points: {}",
|
|
|
|
+ points
|
|
|
|
+ .iter()
|
|
|
|
+ .map(|x| format!("{x}"))
|
|
|
|
+ .collect_vec()
|
|
|
|
+ .join(", ")
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ // trace!("X skew asin tan: {:.3}", self.modifiers.x_skew.asin().tan());
|
|
|
|
+ // trace!("Y skew asin tan: {:.3}", self.modifiers.y_skew.asin().tan());
|
|
|
|
+
|
|
|
|
+ // let skew = |pt: Coordinate| -> Coordinate {
|
|
|
|
+ // Coordinate {
|
|
|
|
+ // x: pt.x + pt.y * self.modifiers.x_skew.asin().tan(),
|
|
|
|
+ // y: pt.y + pt.x * self.modifiers.y_skew.asin().tan(),
|
|
|
|
+ // }
|
|
|
|
+ // };
|
|
|
|
+
|
|
|
|
+ let skewed_points: Vec<Coordinate> = points
|
|
|
|
+ .iter()
|
|
|
|
+ .map(|pt| Coordinate {
|
|
|
|
+ x: pt.x + pt.y * self.modifiers.x_skew.asin().tan(),
|
|
|
|
+ y: pt.y + pt.x * self.modifiers.y_skew.asin().tan(),
|
|
|
|
+ })
|
|
|
|
+ .collect_vec();
|
|
|
|
+
|
|
|
|
+ debug!(
|
|
|
|
+ "Skewed points: {}",
|
|
|
|
+ skewed_points
|
|
|
|
+ .iter()
|
|
|
|
+ .map(|x| format!("{x}"))
|
|
|
|
+ .collect_vec()
|
|
|
|
+ .join(", ")
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ let min_x: f64 = skewed_points.iter().fold(f64::MAX, |acc, pt| acc.min(pt.x));
|
|
|
|
+ let max_x: f64 = skewed_points.iter().fold(f64::MIN, |acc, pt| acc.max(pt.x));
|
|
|
|
+ let min_y: f64 = skewed_points.iter().fold(f64::MAX, |acc, pt| acc.min(pt.y));
|
|
|
|
+ let max_y: f64 = skewed_points.iter().fold(f64::MIN, |acc, pt| acc.max(pt.y));
|
|
|
|
+
|
|
|
|
+ let bounding_box_pts: (Coordinate, Coordinate) = (
|
|
|
|
+ Coordinate { x: min_x, y: min_y },
|
|
|
|
+ Coordinate { x: max_x, y: max_y },
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ debug!(
|
|
|
|
+ "Bounding box (scaled): {}, {}",
|
|
|
|
+ bounding_box_pts.0, bounding_box_pts.1
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ let origin: Coordinate = self.correction()
|
|
|
|
+ + self.scale() * (bounding_box_pts.0 + bounding_box_pts.1)
|
|
|
|
+ / Coordinate::from((2.0, 2.0));
|
|
|
|
+
|
|
|
|
+ let Coordinate {
|
|
|
|
+ x: width,
|
|
|
|
+ y: height,
|
|
|
|
+ } = (bounding_box_pts.1 - bounding_box_pts.0) * self.scale();
|
|
|
|
+
|
|
|
|
+ (origin, width, height)
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
impl Default for ObjectModifier {
|
|
impl Default for ObjectModifier {
|
|
@@ -326,12 +431,10 @@ impl Default for ObjectModifier {
|
|
))]
|
|
))]
|
|
pub struct ScaleValues {
|
|
pub struct ScaleValues {
|
|
pub x_scale: f64, // X scaled ratio on drawn object
|
|
pub x_scale: f64, // X scaled ratio on drawn object
|
|
- // #[br(assert(_unknown_1 == 0.0))]
|
|
|
|
- pub x_skew: f64,
|
|
|
|
|
|
+ pub y_skew: f64,
|
|
#[br(assert(_unknown_2 == 0.0))]
|
|
#[br(assert(_unknown_2 == 0.0))]
|
|
_unknown_2: f64,
|
|
_unknown_2: f64,
|
|
- // #[br(assert(_unknown_3 == 0.0))]
|
|
|
|
- pub y_skew: f64,
|
|
|
|
|
|
+ pub x_skew: f64,
|
|
pub y_scale: f64, // Y scaled ratio on drawn object
|
|
pub y_scale: f64, // Y scaled ratio on drawn object
|
|
#[br(assert(_unknown_4 == 0.0))]
|
|
#[br(assert(_unknown_4 == 0.0))]
|
|
_unknown_4: f64,
|
|
_unknown_4: f64,
|
|
@@ -344,9 +447,9 @@ impl Default for ScaleValues {
|
|
fn default() -> Self {
|
|
fn default() -> Self {
|
|
Self {
|
|
Self {
|
|
x_scale: 1.0.into(),
|
|
x_scale: 1.0.into(),
|
|
- x_skew: 0.0.into(),
|
|
|
|
- _unknown_2: 0.0.into(),
|
|
|
|
y_skew: 0.0.into(),
|
|
y_skew: 0.0.into(),
|
|
|
|
+ _unknown_2: 0.0.into(),
|
|
|
|
+ x_skew: 0.0.into(),
|
|
y_scale: 1.0.into(),
|
|
y_scale: 1.0.into(),
|
|
_unknown_4: 0.0.into(),
|
|
_unknown_4: 0.0.into(),
|
|
correction: (0.0, 0.0).into(),
|
|
correction: (0.0, 0.0).into(),
|