ranim_core/core_item/
vitem.rs

1use color::{AlphaColor, Srgb};
2use glam::{DVec3, Vec3, Vec4};
3
4use crate::{
5    Extract,
6    components::{rgba::Rgba, width::Width},
7    core_item::CoreItem,
8    traits::FillColor,
9};
10
11/// Default vitem stroke width
12pub const DEFAULT_STROKE_WIDTH: f32 = 0.02;
13
14/// The projection of a [`VItem`].
15#[derive(Debug, Clone, Copy, PartialEq, ranim_macros::Interpolatable)]
16pub struct Basis2d {
17    /// The basis vector in the u direction.
18    u: DVec3,
19    /// The basis vector in the v direction.
20    v: DVec3,
21}
22
23impl Default for Basis2d {
24    fn default() -> Self {
25        Self::XY
26    }
27}
28
29impl Basis2d {
30    /// XY
31    pub const XY: Self = Self {
32        u: DVec3::X,
33        v: DVec3::Y,
34    };
35    /// XZ
36    pub const XZ: Self = Self {
37        u: DVec3::X,
38        v: DVec3::Z,
39    };
40    /// YZ
41    pub const YZ: Self = Self {
42        u: DVec3::Y,
43        v: DVec3::Z,
44    };
45    /// Create a new 2d basis from two 3d vectors.
46    pub fn new(u: DVec3, v: DVec3) -> Self {
47        Self {
48            u: u.normalize(),
49            v: v.normalize(),
50        }
51    }
52
53    /// The basis vector in the u direction.
54    pub fn u(&self) -> DVec3 {
55        self.u.normalize()
56    }
57    /// The basis vector in the v direction.
58    pub fn v(&self) -> DVec3 {
59        self.v.normalize()
60    }
61    /// The basis vectors
62    pub fn uv(&self) -> (DVec3, DVec3) {
63        (self.u(), self.v())
64    }
65    /// The corrected basis vector in the u direction.
66    /// This is same as [`Self::u`].
67    pub fn corrected_u(&self) -> DVec3 {
68        self.u.normalize()
69    }
70    /// The corrected basis vector in the v direction.
71    /// This is recalculated to ensure orthogonality.
72    pub fn corrected_v(&self) -> DVec3 {
73        let normal = self.u.cross(self.v);
74        normal.cross(self.u).normalize()
75    }
76    /// The corrected basis vectos.
77    /// This is recalculated to ensure orthogonality.
78    pub fn corrected_uv(&self) -> (DVec3, DVec3) {
79        (self.corrected_u(), self.corrected_v())
80    }
81    /// Get the normal vector of the projection target plane.
82    #[inline]
83    pub fn normal(&self) -> DVec3 {
84        self.u.cross(self.v).normalize()
85    }
86    /// Rotate the basis vectors around the given axis.
87    pub fn rotate_on_axis(&mut self, axis: DVec3, angle: f64) {
88        self.u = DVec3::rotate_axis(self.u, axis, angle).normalize();
89        self.v = DVec3::rotate_axis(self.v, axis, angle).normalize();
90    }
91}
92
93#[derive(Debug, Clone, PartialEq)]
94/// A primitive for rendering a vitem.
95pub struct VItem {
96    /// The base point of the item, a.k.a. the origin of the item's local coordinate system.
97    pub origin: Vec3,
98    /// The basis vectors of the item's local coordinate system. Normalized.
99    pub basis: Basis2d,
100    /// The points of the item in the item's local coordinate system.
101    /// (x, y, z, is_closed)
102    pub points: Vec<Vec4>,
103    /// Fill rgbas, see [`Rgba`].
104    pub fill_rgbas: Vec<Rgba>,
105    /// Stroke rgbs, see [`Rgba`].
106    pub stroke_rgbas: Vec<Rgba>,
107    /// Stroke widths, see [`Width`].
108    pub stroke_widths: Vec<Width>,
109}
110
111impl Default for VItem {
112    fn default() -> Self {
113        Self {
114            origin: Vec3::ZERO,
115            basis: Basis2d::default(),
116            points: vec![Vec4::ZERO; 3],
117            stroke_widths: vec![Width::default(); 2],
118            stroke_rgbas: vec![Rgba::default(); 2],
119            fill_rgbas: vec![Rgba::default(); 2],
120        }
121    }
122}
123
124impl Extract for VItem {
125    type Target = CoreItem;
126    fn extract_into(&self, buf: &mut Vec<Self::Target>) {
127        buf.push(CoreItem::VItem(self.clone()));
128    }
129}
130
131impl FillColor for VItem {
132    fn fill_color(&self) -> AlphaColor<Srgb> {
133        let Rgba(rgba) = self.fill_rgbas[0];
134        AlphaColor::new([rgba.x, rgba.y, rgba.z, rgba.w])
135    }
136    fn set_fill_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
137        self.fill_rgbas.fill(color.into());
138        self
139    }
140    fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self {
141        self.fill_rgbas
142            .iter_mut()
143            .for_each(|rgba| rgba.0.w = opacity);
144        self
145    }
146}