1use embedded_graphics_core::pixelcolor::Rgb565;
2
3#[cfg(not(feature = "std"))]
4use crate::math::F32Ext as _;
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub enum RenderQuality {
8 Low,
9 Medium,
10 High,
11}
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub enum AntiAliasMode {
15 None,
16 Coverage,
17 Subpixel,
18}
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
21pub enum StrokeCap {
22 Butt,
23 Round,
24}
25
26#[derive(Clone, Copy, Debug, PartialEq, Eq)]
27pub enum StrokeJoin {
28 Miter,
29 Round,
30}
31
32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub struct StrokeStyle {
34 pub color: Rgb565,
35 pub width: u8,
36 pub antialias: bool,
37 pub antialias_mode: AntiAliasMode,
38 pub cap: StrokeCap,
39 pub join: StrokeJoin,
40}
41
42impl StrokeStyle {
43 pub const fn new(color: Rgb565) -> Self {
44 Self {
45 color,
46 width: 1,
47 antialias: false,
48 antialias_mode: AntiAliasMode::None,
49 cap: StrokeCap::Butt,
50 join: StrokeJoin::Miter,
51 }
52 }
53
54 pub const fn with_width(mut self, width: u8) -> Self {
55 self.width = if width == 0 { 1 } else { width };
56 self
57 }
58
59 pub const fn with_antialias(mut self, antialias: bool) -> Self {
60 self.antialias = antialias;
61 if antialias {
62 if let AntiAliasMode::None = self.antialias_mode {
63 self.antialias_mode = AntiAliasMode::Coverage;
64 }
65 }
66 if !antialias {
67 self.antialias_mode = AntiAliasMode::None;
68 }
69 self
70 }
71
72 pub const fn with_antialias_mode(mut self, mode: AntiAliasMode) -> Self {
73 self.antialias_mode = mode;
74 self.antialias = !matches!(mode, AntiAliasMode::None);
75 self
76 }
77
78 pub const fn with_cap(mut self, cap: StrokeCap) -> Self {
79 self.cap = cap;
80 self
81 }
82
83 pub const fn with_join(mut self, join: StrokeJoin) -> Self {
84 self.join = join;
85 self
86 }
87}
88
89#[derive(Clone, Copy, Debug, PartialEq)]
90pub struct Transform2D {
91 pub m11: f32,
92 pub m12: f32,
93 pub m21: f32,
94 pub m22: f32,
95 pub tx: f32,
96 pub ty: f32,
97}
98
99impl Transform2D {
100 pub const IDENTITY: Self = Self {
101 m11: 1.0,
102 m12: 0.0,
103 m21: 0.0,
104 m22: 1.0,
105 tx: 0.0,
106 ty: 0.0,
107 };
108
109 pub const fn translation(x: f32, y: f32) -> Self {
110 Self {
111 tx: x,
112 ty: y,
113 ..Self::IDENTITY
114 }
115 }
116
117 pub const fn scale(x: f32, y: f32) -> Self {
118 Self {
119 m11: x,
120 m22: y,
121 ..Self::IDENTITY
122 }
123 }
124
125 pub fn rotation(deg: f32) -> Self {
126 let r = deg.to_radians();
127 Self {
128 m11: r.cos(),
129 m12: -r.sin(),
130 m21: r.sin(),
131 m22: r.cos(),
132 ..Self::IDENTITY
133 }
134 }
135
136 pub fn skew(x_deg: f32, y_deg: f32) -> Self {
137 Self {
138 m12: x_deg.to_radians().tan(),
139 m21: y_deg.to_radians().tan(),
140 ..Self::IDENTITY
141 }
142 }
143
144 pub fn then(self, rhs: Self) -> Self {
145 Self {
146 m11: self.m11 * rhs.m11 + self.m12 * rhs.m21,
147 m12: self.m11 * rhs.m12 + self.m12 * rhs.m22,
148 m21: self.m21 * rhs.m11 + self.m22 * rhs.m21,
149 m22: self.m21 * rhs.m12 + self.m22 * rhs.m22,
150 tx: self.m11 * rhs.tx + self.m12 * rhs.ty + self.tx,
151 ty: self.m21 * rhs.tx + self.m22 * rhs.ty + self.ty,
152 }
153 }
154
155 #[inline(always)]
156 pub fn is_identity(self) -> bool {
157 self.m11 == 1.0
158 && self.m12 == 0.0
159 && self.m21 == 0.0
160 && self.m22 == 1.0
161 && self.tx == 0.0
162 && self.ty == 0.0
163 }
164
165 #[inline(always)]
166 pub fn apply(self, x: i32, y: i32) -> (i32, i32) {
167 if self.is_identity() {
168 (x, y)
169 } else {
170 let xf = x as f32;
171 let yf = y as f32;
172 (
173 (self.m11 * xf + self.m12 * yf + self.tx).round() as i32,
174 (self.m21 * xf + self.m22 * yf + self.ty).round() as i32,
175 )
176 }
177 }
178
179 #[inline(always)]
180 pub fn apply_f32(self, x: f32, y: f32) -> (f32, f32) {
181 if self.is_identity() {
182 (x, y)
183 } else {
184 (
185 self.m11 * x + self.m12 * y + self.tx,
186 self.m21 * x + self.m22 * y + self.ty,
187 )
188 }
189 }
190
191 pub fn inverse(self) -> Option<Self> {
192 let det = self.m11 * self.m22 - self.m12 * self.m21;
193 if det.abs() < 1e-7 {
194 return None;
195 }
196 let inv_det = 1.0 / det;
197 let m11 = self.m22 * inv_det;
198 let m12 = -self.m12 * inv_det;
199 let m21 = -self.m21 * inv_det;
200 let m22 = self.m11 * inv_det;
201 let tx = (self.m12 * self.ty - self.m22 * self.tx) * inv_det;
202 let ty = (self.m21 * self.tx - self.m11 * self.ty) * inv_det;
203 Some(Self {
204 m11,
205 m12,
206 m21,
207 m22,
208 tx,
209 ty,
210 })
211 }
212}