schematic_mesher/types/
transform.rs

1//! Transform types for block and element rotations.
2
3use super::Axis;
4use serde::{Deserialize, Serialize};
5
6/// Block-level transform from blockstate variant.
7#[derive(Debug, Clone, Copy, Default)]
8pub struct BlockTransform {
9    /// X rotation in degrees (0, 90, 180, 270).
10    pub x: i32,
11    /// Y rotation in degrees (0, 90, 180, 270).
12    pub y: i32,
13    /// If true, UV coordinates don't rotate with the block.
14    pub uvlock: bool,
15}
16
17impl BlockTransform {
18    pub fn new(x: i32, y: i32, uvlock: bool) -> Self {
19        Self { x, y, uvlock }
20    }
21
22    /// Check if this is an identity transform (no rotation).
23    pub fn is_identity(&self) -> bool {
24        self.x == 0 && self.y == 0
25    }
26}
27
28/// Element-level rotation from model element.
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct ElementRotation {
31    /// Origin point for rotation (in 0-16 Minecraft coordinates).
32    #[serde(default = "default_origin")]
33    pub origin: [f32; 3],
34    /// Axis to rotate around.
35    pub axis: Axis,
36    /// Rotation angle in degrees (-45 to 45, in 22.5 increments).
37    pub angle: f32,
38    /// Whether to rescale the element after rotation.
39    #[serde(default)]
40    pub rescale: bool,
41}
42
43fn default_origin() -> [f32; 3] {
44    [8.0, 8.0, 8.0]
45}
46
47impl ElementRotation {
48    /// Convert origin from Minecraft coordinates (0-16) to normalized (-0.5 to 0.5).
49    pub fn normalized_origin(&self) -> [f32; 3] {
50        [
51            self.origin[0] / 16.0 - 0.5,
52            self.origin[1] / 16.0 - 0.5,
53            self.origin[2] / 16.0 - 0.5,
54        ]
55    }
56
57    /// Get the angle in radians.
58    pub fn angle_radians(&self) -> f32 {
59        self.angle.to_radians()
60    }
61
62    /// Get the rescale factor for this rotation.
63    /// When rescale is true, the element is scaled to maintain its original size.
64    pub fn rescale_factor(&self) -> f32 {
65        if self.rescale {
66            1.0 / self.angle_radians().cos()
67        } else {
68            1.0
69        }
70    }
71}