alpha2_engine/layout/
draw.rs1use super::paint::{PaintItem, Placement};
4use crate::TextTexture;
5use alpha2_render::{
6 BlendMode, GraphError, GraphLayer, LayerTransform, RenderError, RenderGraph, RenderNodeId,
7 RenderSize,
8};
9use std::sync::Arc;
10
11#[derive(Debug)]
15pub struct PreparedLayout {
16 pub(crate) items: Vec<PaintItem>,
17 pub(crate) texts: Vec<Option<u64>>,
18}
19
20#[derive(Clone, Debug)]
22pub(crate) struct LaidOut<'t> {
23 pub(crate) layout: Arc<PreparedLayout>,
24 pub(crate) texts: Vec<Option<TextTexture<'t>>>,
25}
26
27impl<'t> LaidOut<'t> {
28 pub(crate) fn attach(
30 layout: Arc<PreparedLayout>,
31 frames: &'t dyn crate::FrameProvider,
32 ) -> Option<Self> {
33 let texts = layout
34 .texts
35 .iter()
36 .map(|key| {
37 key.map(|key| frames.text(key))
38 .map_or(Some(None), |text| text.map(Some))
39 })
40 .collect::<Option<Vec<_>>>()?;
41 Some(Self { layout, texts })
42 }
43
44 pub(crate) fn add_to(&self, graph: &mut RenderGraph<'t>) -> Result<RenderNodeId, RenderError> {
45 let layers = self.layers(graph, &self.layout.items)?;
46 graph
47 .add_composite(layers)
48 .map_err(GraphError::into_render_error)
49 }
50
51 fn layers(
52 &self,
53 graph: &mut RenderGraph<'t>,
54 items: &[PaintItem],
55 ) -> Result<Vec<GraphLayer>, RenderError> {
56 let size = graph.size();
57 let canvas = [size.width, size.height];
58 let mut layers = Vec::with_capacity(items.len());
59 for item in items {
60 let (source, place, extent) = match item {
61 PaintItem::Vector { scene, place } => {
62 (graph.add_vector(Arc::clone(scene)), *place, canvas)
63 }
64 PaintItem::Text { index, place } => {
65 let texture = self
66 .texts
67 .get(*index)
68 .copied()
69 .flatten()
70 .ok_or(RenderError::MissingText)?;
71 let visual = layer_transform(*place, [texture.width, texture.height], size);
72 layers.push(crate::frame::text_layer(graph, texture, visual)?);
73 continue;
74 }
75 PaintItem::Group { items, clip, place } => {
76 let inner = self.layers(graph, items)?;
77 let mut node = graph
78 .add_composite(inner)
79 .map_err(GraphError::into_render_error)?;
80 if let Some(clip) = clip {
81 let coverage = graph.add_vector(Arc::clone(clip));
82 node = crate::frame::coverage_mask(
83 graph,
84 node,
85 &[(coverage, false, alpha2_model::MaskMode::Add)],
86 )?;
87 }
88 (node, *place, canvas)
89 }
90 };
91 layers.push(GraphLayer {
92 source,
93 visual: layer_transform(place, extent, size),
94 blend_mode: BlendMode::Normal,
95 });
96 }
97 Ok(layers)
98 }
99}
100
101#[allow(clippy::cast_possible_truncation, clippy::cast_precision_loss)]
103fn layer_transform(place: Placement, extent: [u32; 2], size: RenderSize) -> LayerTransform {
104 let output = [f64::from(size.width), f64::from(size.height)];
105 let extent = extent.map(f64::from);
106 LayerTransform {
107 position: [
108 (place.position[0] / output[0]) as f32,
109 (place.position[1] / output[1]) as f32,
110 ],
111 anchor: [
112 (place.anchor[0] / extent[0]) as f32,
113 (place.anchor[1] / extent[1]) as f32,
114 ],
115 scale: [
116 (place.scale[0] * extent[0] / output[0]) as f32,
117 (place.scale[1] * extent[1] / output[1]) as f32,
118 ],
119 rotation_degrees: place.rotation_degrees as f32,
120 opacity: place.opacity,
121 }
122}