1#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
22pub struct Color {
23 pub r: u8,
24 pub g: u8,
25 pub b: u8,
26 pub a: u8,
27}
28
29impl Color {
30 pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
32 Self { r, g, b, a: 255 }
33 }
34
35 pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
37 Self { r, g, b, a }
38 }
39
40 pub const fn hex(hex: u32) -> Self {
42 Self {
43 r: ((hex >> 16) & 0xFF) as u8,
44 g: ((hex >> 8) & 0xFF) as u8,
45 b: (hex & 0xFF) as u8,
46 a: 255,
47 }
48 }
49
50 #[must_use]
52 pub const fn with_alpha(self, a: u8) -> Self {
53 Self { a, ..self }
54 }
55
56 pub const WHITE: Self = Self::rgb(255, 255, 255);
57 pub const BLACK: Self = Self::rgb(0, 0, 0);
58 pub const RED: Self = Self::rgb(255, 0, 0);
59 pub const GREEN: Self = Self::rgb(0, 255, 0);
60 pub const BLUE: Self = Self::rgb(0, 0, 255);
61 pub const YELLOW: Self = Self::rgb(255, 255, 0);
62 pub const CYAN: Self = Self::rgb(0, 255, 255);
63 pub const MAGENTA: Self = Self::rgb(255, 0, 255);
64 pub const TRANSPARENT: Self = Self::rgba(0, 0, 0, 0);
65}
66
67impl Default for Color {
68 fn default() -> Self {
69 Self::WHITE
70 }
71}
72
73#[derive(Clone, Copy, Debug, Default, PartialEq)]
75pub struct Point2D {
76 pub x: f32,
77 pub y: f32,
78}
79
80impl Point2D {
81 pub const fn new(x: f32, y: f32) -> Self {
82 Self { x, y }
83 }
84
85 pub const ZERO: Self = Self::new(0.0, 0.0);
86}
87
88#[derive(Clone, Copy, Debug, Default, PartialEq)]
90pub struct Rect {
91 pub x: f32,
92 pub y: f32,
93 pub w: f32,
94 pub h: f32,
95}
96
97impl Rect {
98 pub const fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
99 Self { x, y, w, h }
100 }
101
102 pub const fn from_point_size(origin: Point2D, w: f32, h: f32) -> Self {
104 Self {
105 x: origin.x,
106 y: origin.y,
107 w,
108 h,
109 }
110 }
111
112 pub fn contains(&self, px: f32, py: f32) -> bool {
115 px >= self.x && py >= self.y && px < self.x + self.w && py < self.y + self.h
116 }
117
118 pub fn origin(&self) -> Point2D {
119 Point2D::new(self.x, self.y)
120 }
121
122 pub fn center(&self) -> Point2D {
123 Point2D::new(self.x + self.w / 2.0, self.y + self.h / 2.0)
124 }
125}
126
127#[derive(Clone, Copy, Debug, PartialEq)]
129pub struct GradientStop {
130 pub offset: f32,
131 pub color: Color,
132}
133
134impl GradientStop {
135 pub const fn new(offset: f32, color: Color) -> Self {
136 Self { offset, color }
137 }
138}
139
140pub struct Canvas;
145
146impl Canvas {
147 pub fn new() -> Self {
149 Self
150 }
151
152 pub fn clear(&self, color: Color) {
154 crate::canvas_clear(color.r, color.g, color.b, color.a);
155 }
156
157 pub fn fill_rect(&self, rect: Rect, color: Color) {
159 crate::canvas_rect(
160 rect.x, rect.y, rect.w, rect.h, color.r, color.g, color.b, color.a,
161 );
162 }
163
164 pub fn fill_rounded_rect(&self, rect: Rect, radius: f32, color: Color) {
166 crate::canvas_rounded_rect(
167 rect.x, rect.y, rect.w, rect.h, radius, color.r, color.g, color.b, color.a,
168 );
169 }
170
171 pub fn fill_circle(&self, center: Point2D, radius: f32, color: Color) {
173 crate::canvas_circle(
174 center.x, center.y, radius, color.r, color.g, color.b, color.a,
175 );
176 }
177
178 pub fn arc(
180 &self,
181 center: Point2D,
182 radius: f32,
183 start_angle: f32,
184 end_angle: f32,
185 thickness: f32,
186 color: Color,
187 ) {
188 crate::canvas_arc(
189 center.x,
190 center.y,
191 radius,
192 start_angle,
193 end_angle,
194 color.r,
195 color.g,
196 color.b,
197 color.a,
198 thickness,
199 );
200 }
201
202 pub fn bezier(
204 &self,
205 from: Point2D,
206 ctrl1: Point2D,
207 ctrl2: Point2D,
208 to: Point2D,
209 thickness: f32,
210 color: Color,
211 ) {
212 crate::canvas_bezier(
213 from.x, from.y, ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, to.x, to.y, color.r, color.g,
214 color.b, color.a, thickness,
215 );
216 }
217
218 pub fn text(&self, text: &str, pos: Point2D, size: f32, color: Color) {
220 crate::canvas_text(pos.x, pos.y, size, color.r, color.g, color.b, color.a, text);
221 }
222
223 pub fn line(&self, from: Point2D, to: Point2D, thickness: f32, color: Color) {
225 crate::canvas_line(
226 from.x, from.y, to.x, to.y, color.r, color.g, color.b, color.a, thickness,
227 );
228 }
229
230 pub fn image(&self, rect: Rect, data: &[u8]) {
232 crate::canvas_image(rect.x, rect.y, rect.w, rect.h, data);
233 }
234
235 pub fn linear_gradient(&self, rect: Rect, stops: &[GradientStop]) {
237 let raw: Vec<(f32, u8, u8, u8, u8)> = stops
238 .iter()
239 .map(|s| (s.offset, s.color.r, s.color.g, s.color.b, s.color.a))
240 .collect();
241 crate::canvas_gradient(
242 rect.x,
243 rect.y,
244 rect.w,
245 rect.h,
246 crate::GRADIENT_LINEAR,
247 rect.x,
248 rect.y,
249 rect.x + rect.w,
250 rect.y + rect.h,
251 &raw,
252 );
253 }
254
255 pub fn radial_gradient(&self, rect: Rect, stops: &[GradientStop]) {
257 let raw: Vec<(f32, u8, u8, u8, u8)> = stops
258 .iter()
259 .map(|s| (s.offset, s.color.r, s.color.g, s.color.b, s.color.a))
260 .collect();
261 let cx = rect.x + rect.w / 2.0;
262 let cy = rect.y + rect.h / 2.0;
263 let r = rect.w.max(rect.h) / 2.0;
264 crate::canvas_gradient(
265 rect.x,
266 rect.y,
267 rect.w,
268 rect.h,
269 crate::GRADIENT_RADIAL,
270 cx,
271 cy,
272 0.0,
273 r,
274 &raw,
275 );
276 }
277
278 pub fn save(&self) {
280 crate::canvas_save();
281 }
282
283 pub fn restore(&self) {
285 crate::canvas_restore();
286 }
287
288 pub fn translate(&self, tx: f32, ty: f32) {
290 crate::canvas_transform(1.0, 0.0, 0.0, 1.0, tx, ty);
291 }
292
293 pub fn rotate(&self, angle: f32) {
295 let (s, c) = (angle.sin(), angle.cos());
296 crate::canvas_transform(c, s, -s, c, 0.0, 0.0);
297 }
298
299 pub fn scale(&self, sx: f32, sy: f32) {
301 crate::canvas_transform(sx, 0.0, 0.0, sy, 0.0, 0.0);
302 }
303
304 pub fn transform(&self, a: f32, b: f32, c: f32, d: f32, tx: f32, ty: f32) {
306 crate::canvas_transform(a, b, c, d, tx, ty);
307 }
308
309 pub fn clip(&self, rect: Rect) {
311 crate::canvas_clip(rect.x, rect.y, rect.w, rect.h);
312 }
313
314 pub fn set_opacity(&self, alpha: f32) {
316 crate::canvas_opacity(alpha);
317 }
318
319 pub fn dimensions(&self) -> (u32, u32) {
321 crate::canvas_dimensions()
322 }
323
324 pub fn width(&self) -> u32 {
326 self.dimensions().0
327 }
328
329 pub fn height(&self) -> u32 {
331 self.dimensions().1
332 }
333}
334
335impl Default for Canvas {
336 fn default() -> Self {
337 Self::new()
338 }
339}