1use crate::math::{Color, Rect, Vec2};
2use core::{
3 assets::{asset::AssetId, database::AssetsDatabase},
4 error::*,
5 Ignite, Scalar,
6};
7use serde::{Deserialize, Serialize};
8use std::{borrow::Cow, ops::Range};
9
10#[derive(Ignite, Debug, Default, Clone, Serialize, Deserialize)]
11pub struct Rectangle {
12 pub color: Color,
13 pub rect: Rect,
14}
15
16impl Rectangle {
17 pub fn align(mut self, factor: Vec2) -> Self {
18 self.rect = self.rect.align(factor);
19 self
20 }
21}
22
23#[derive(Ignite, Debug, Copy, Clone, Serialize, Deserialize)]
24pub enum TextAlign {
25 Left,
26 Center,
27 Right,
28}
29
30impl Default for TextAlign {
31 fn default() -> Self {
32 TextAlign::Left
33 }
34}
35
36#[derive(Ignite, Debug, Copy, Clone, Serialize, Deserialize)]
37pub enum TextBaseLine {
38 Top,
39 Middle,
40 Bottom,
41 Alphabetic,
42 Hanging,
43}
44
45impl Default for TextBaseLine {
46 fn default() -> Self {
47 TextBaseLine::Top
48 }
49}
50
51#[derive(Ignite, Debug, Default, Clone, Serialize, Deserialize)]
52pub struct Text<'a> {
53 #[serde(default)]
54 pub color: Color,
55 #[serde(default)]
56 pub font: Cow<'a, str>,
57 #[serde(default)]
58 pub align: TextAlign,
59 #[serde(default)]
60 pub baseline: TextBaseLine,
61 #[serde(default)]
62 pub text: Cow<'a, str>,
63 #[serde(default)]
64 pub position: Vec2,
65 #[serde(default = "Text::default_size")]
66 pub size: Scalar,
67 #[serde(default)]
68 pub max_width: Option<Scalar>,
69}
70
71impl<'a> Text<'a> {
72 fn default_size() -> Scalar {
73 32.0
74 }
75
76 pub fn new(font: &'a str, text: &'a str) -> Self {
77 Self {
78 color: Default::default(),
79 font: font.into(),
80 align: Default::default(),
81 baseline: Default::default(),
82 text: text.into(),
83 position: 0.0.into(),
84 size: 32.0,
85 max_width: None,
86 }
87 }
88
89 pub fn new_owned(font: String, text: String) -> Self {
90 Self {
91 color: Default::default(),
92 font: font.into(),
93 align: Default::default(),
94 baseline: Default::default(),
95 text: text.into(),
96 position: 0.0.into(),
97 size: 32.0,
98 max_width: None,
99 }
100 }
101
102 pub fn color(mut self, color: Color) -> Self {
103 self.color = color;
104 self
105 }
106
107 pub fn align(mut self, align: TextAlign) -> Self {
108 self.align = align;
109 self
110 }
111
112 pub fn baseline(mut self, baseline: TextBaseLine) -> Self {
113 self.baseline = baseline;
114 self
115 }
116
117 pub fn position(mut self, position: Vec2) -> Self {
118 self.position = position;
119 self
120 }
121
122 pub fn size(mut self, size: Scalar) -> Self {
123 self.size = size;
124 self
125 }
126}
127
128#[derive(Ignite, Debug, Clone, Serialize, Deserialize)]
129pub enum PathElement {
130 MoveTo(Vec2),
131 LineTo(Vec2),
132 BezierCurveTo(Vec2, Vec2, Vec2),
134 QuadraticCurveTo(Vec2, Vec2),
136 Arc(Vec2, Scalar, Range<Scalar>),
138 Ellipse(Vec2, Vec2, Scalar, Range<Scalar>),
140 Rectangle(Rect),
141}
142
143#[derive(Ignite, Debug, Default, Clone, Serialize, Deserialize)]
144pub struct Path {
145 #[serde(default)]
146 pub color: Color,
147 #[serde(default)]
148 pub elements: Vec<PathElement>,
149}
150
151#[derive(Ignite, Debug, Default, Clone, Serialize, Deserialize)]
152pub struct Mask {
153 #[serde(default)]
154 pub elements: Vec<PathElement>,
155}
156
157#[derive(Ignite, Debug, Default, Copy, Clone, Serialize, Deserialize)]
158pub struct TriangleFace {
159 #[serde(default)]
160 pub a: usize,
161 #[serde(default)]
162 pub b: usize,
163 #[serde(default)]
164 pub c: usize,
165}
166
167impl TriangleFace {
168 pub fn new(a: usize, b: usize, c: usize) -> Self {
169 Self { a, b, c }
170 }
171}
172
173#[derive(Ignite, Debug, Default, Clone, Serialize, Deserialize)]
174pub struct Triangles<'a> {
175 #[serde(default)]
176 pub image: Cow<'a, str>,
177 #[serde(default)]
178 pub color: Color,
179 #[serde(default)]
181 pub vertices: Vec<(Vec2, Vec2)>,
182 #[serde(default)]
183 pub faces: Vec<TriangleFace>,
184}
185
186#[derive(Ignite, Debug, Default, Clone, Serialize, Deserialize)]
187pub struct Image<'a> {
188 #[serde(default)]
189 pub image: Cow<'a, str>,
190 #[serde(default)]
191 pub source: Option<Rect>,
192 #[serde(default)]
193 pub destination: Option<Rect>,
194 #[serde(default)]
195 pub alignment: Vec2,
196}
197
198impl<'a> Image<'a> {
199 pub fn new(image: &'a str) -> Self {
200 Self {
201 image: image.into(),
202 source: None,
203 destination: None,
204 alignment: 0.0.into(),
205 }
206 }
207
208 pub fn new_owned(image: String) -> Self {
209 Self {
210 image: image.into(),
211 source: None,
212 destination: None,
213 alignment: 0.0.into(),
214 }
215 }
216
217 pub fn source(mut self, rect: Option<Rect>) -> Self {
218 self.source = rect;
219 self
220 }
221
222 pub fn destination(mut self, rect: Option<Rect>) -> Self {
223 self.destination = rect;
224 self
225 }
226
227 pub fn align(mut self, factor: Vec2) -> Self {
228 self.alignment = factor;
229 self
230 }
231}
232
233#[derive(Ignite, Debug, Clone, Serialize, Deserialize)]
234pub enum Renderable<'a> {
235 None,
236 Rectangle(Rectangle),
237 FullscreenRectangle(Color),
238 Text(Text<'a>),
239 Path(Path),
240 Mask(Mask),
241 Image(Image<'a>),
242 Triangles(Triangles<'a>),
243 Commands(Vec<Command<'a>>),
244}
245
246impl<'a> Renderable<'a> {
247 pub fn is_none(&self) -> bool {
248 matches!(self, Self::None)
249 }
250}
251
252impl<'a> From<()> for Renderable<'a> {
253 fn from(_: ()) -> Self {
254 Renderable::None
255 }
256}
257
258impl<'a> From<Rectangle> for Renderable<'a> {
259 fn from(rect: Rectangle) -> Self {
260 Renderable::Rectangle(rect)
261 }
262}
263
264impl<'a> From<Text<'a>> for Renderable<'a> {
265 fn from(text: Text<'a>) -> Self {
266 Renderable::Text(text)
267 }
268}
269
270impl<'a> From<Path> for Renderable<'a> {
271 fn from(path: Path) -> Self {
272 Renderable::Path(path)
273 }
274}
275
276impl<'a> From<Mask> for Renderable<'a> {
277 fn from(mask: Mask) -> Self {
278 Renderable::Mask(mask)
279 }
280}
281
282impl<'a> From<Image<'a>> for Renderable<'a> {
283 fn from(image: Image<'a>) -> Self {
284 Renderable::Image(image)
285 }
286}
287
288impl<'a> From<Triangles<'a>> for Renderable<'a> {
289 fn from(triangles: Triangles<'a>) -> Self {
290 Renderable::Triangles(triangles)
291 }
292}
293
294#[derive(Ignite, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
295pub enum Effect {
296 SourceOver,
297 SourceIn,
298 SourceOut,
299 SourceAtop,
300 DestinationOver,
301 DestinationIn,
302 DestinationOut,
303 DestinationAtop,
304 Lighter,
305 Copy,
306 Xor,
307 Multiply,
308 Screen,
309 Overlay,
310 Darken,
311 Lighten,
312 ColorDodge,
313 ColorBurn,
314 HardLight,
315 SoftLight,
316 Difference,
317 Exclusion,
318 Hue,
319 Saturation,
320 Color,
321 Luminosity,
322}
323
324impl Default for Effect {
325 fn default() -> Self {
326 Effect::SourceOver
327 }
328}
329
330impl ToString for Effect {
331 fn to_string(&self) -> String {
332 use Effect::*;
333 match self {
334 SourceOver => "source-over",
335 SourceIn => "source-in",
336 SourceOut => "source-out",
337 SourceAtop => "source-atop",
338 DestinationOver => "destination-over",
339 DestinationIn => "destination-in",
340 DestinationOut => "destination-out",
341 DestinationAtop => "destination-atop",
342 Lighter => "lighter",
343 Copy => "copy",
344 Xor => "xor",
345 Multiply => "multiply",
346 Screen => "screen",
347 Overlay => "overlay",
348 Darken => "darken",
349 Lighten => "lighten",
350 ColorDodge => "color-dodge",
351 ColorBurn => "color-burn",
352 HardLight => "hard-light",
353 SoftLight => "soft-light",
354 Difference => "difference",
355 Exclusion => "exclusion",
356 Hue => "hue",
357 Saturation => "saturation",
358 Color => "color",
359 Luminosity => "luminosity",
360 }
361 .to_owned()
362 }
363}
364
365#[derive(Ignite, Debug, Clone, Serialize, Deserialize)]
366pub enum Command<'a> {
367 None,
368 Draw(Renderable<'a>),
369 Stroke(Scalar, Renderable<'a>),
371 Transform(Scalar, Scalar, Scalar, Scalar, Scalar, Scalar),
373 Effect(Effect),
374 Alpha(Scalar),
375 Filter(Cow<'a, str>),
376 Smoothing(bool),
377 Store,
378 Restore,
379}
380
381#[derive(Debug, Default, Clone, Serialize, Deserialize)]
382pub struct Stats {
383 pub view_size: Vec2,
384 pub render_ops: usize,
385 pub renderables: usize,
386 pub fps: Scalar,
387 pub delta_time: Scalar,
388 pub images_count: usize,
389 pub fontfaces_count: usize,
390 pub surfaces_count: usize,
391}
392
393#[derive(Debug, Clone, Serialize, Deserialize)]
394pub struct RenderState {
395 pub clear_color: Option<Color>,
396 pub image_smoothing: bool,
397 pub image_source_inner_margin: Scalar,
398 pub triangles_outer_margin: Scalar,
399 stats: Stats,
400}
401
402impl Default for RenderState {
403 fn default() -> Self {
404 Self {
405 clear_color: Some(Color::black()),
406 image_smoothing: true,
407 image_source_inner_margin: 0.0,
408 triangles_outer_margin: 0.0,
409 stats: Stats::default(),
410 }
411 }
412}
413
414impl RenderState {
415 pub fn new(clear_color: Option<Color>) -> Self {
416 Self {
417 clear_color,
418 image_smoothing: true,
419 image_source_inner_margin: 0.0,
420 triangles_outer_margin: 0.0,
421 stats: Stats::default(),
422 }
423 }
424
425 pub fn clear_color(mut self, clear_color: Option<Color>) -> Self {
426 self.clear_color = clear_color;
427 self
428 }
429
430 pub fn image_smoothing(mut self, image_smoothing: bool) -> Self {
431 self.image_smoothing = image_smoothing;
432 self
433 }
434
435 pub fn image_source_inner_margin(mut self, image_source_inner_margin: Scalar) -> Self {
436 self.image_source_inner_margin = image_source_inner_margin;
437 self
438 }
439
440 pub fn triangles_outer_margin(mut self, triangles_outer_margin: Scalar) -> Self {
441 self.triangles_outer_margin = triangles_outer_margin;
442 self
443 }
444
445 pub fn stats(&self) -> &Stats {
446 &self.stats
447 }
448
449 pub fn set_stats(&mut self, stats: Stats) {
450 self.stats = stats;
451 }
452}
453
454pub trait CompositeRenderer: Send + Sync {
455 fn execute<'a, I>(&mut self, commands: I) -> Result<(usize, usize)>
457 where
458 I: IntoIterator<Item = Command<'a>>;
459
460 fn images_count(&self) -> usize {
461 0
462 }
463
464 fn fontfaces_count(&self) -> usize {
465 0
466 }
467
468 fn surfaces_count(&self) -> usize {
469 0
470 }
471
472 fn state(&self) -> &RenderState;
473
474 fn state_mut(&mut self) -> &mut RenderState;
475
476 fn view_size(&self) -> Vec2;
477
478 fn update_state(&mut self) {}
479
480 fn update_cache(&mut self, _assets: &AssetsDatabase) {}
481
482 fn create_surface(&mut self, name: &str, width: usize, height: usize) -> bool;
483
484 fn destroy_surface(&mut self, name: &str) -> bool;
485
486 fn has_surface(&mut self, name: &str) -> bool;
487
488 fn get_surface_size(&self, name: &str) -> Option<(usize, usize)>;
489
490 fn update_surface<'a, I>(&mut self, name: &str, commands: I) -> Result<(usize, usize)>
491 where
492 I: IntoIterator<Item = Command<'a>>;
493}
494
495pub trait CompositeRendererResources<T> {
496 fn add_resource(&mut self, id: String, resource: T) -> Result<AssetId>;
497
498 fn remove_resource(&mut self, id: AssetId) -> Result<T>;
499}