1use crate::{color::Color, engine::{self, ShapeRotationConfig, VisualRotationConfig}, math::BoundingBox, elements::BorderPosition, renderer::ImageSource, shaders::ShaderConfig};
2
3#[derive(Debug, Clone)]
5pub struct Rectangle {
6 pub color: Color,
8 pub corner_radii: CornerRadii,
10}
11
12#[derive(Debug, Clone)]
14pub struct Text {
15 pub text: String,
17 pub color: Color,
19 pub font_size: u16,
21 pub letter_spacing: u16,
23 pub line_height: u16,
25 pub font_asset: Option<&'static crate::renderer::FontAsset>,
27}
28
29#[derive(Debug, Clone)]
31pub struct CornerRadii {
32 pub top_left: f32,
34 pub top_right: f32,
36 pub bottom_left: f32,
38 pub bottom_right: f32,
40}
41
42#[derive(Debug, Clone)]
44pub struct BorderWidth {
45 pub left: u16,
47 pub right: u16,
49 pub top: u16,
51 pub bottom: u16,
53 pub between_children: u16,
55}
56
57#[derive(Debug, Clone)]
59pub struct Border {
60 pub color: Color,
62 pub corner_radii: CornerRadii,
64 pub width: BorderWidth,
66 pub position: BorderPosition,
68}
69
70#[derive(Debug, Clone)]
72pub struct Image {
73 pub background_color: Color,
75 pub corner_radii: CornerRadii,
77 pub data: ImageSource,
79}
80
81#[derive(Debug, Clone)]
83pub struct Custom<CustomElementData> {
84 pub background_color: Color,
86 pub corner_radii: CornerRadii,
88 pub data: CustomElementData,
90}
91
92impl CornerRadii {
93 pub fn clamp_to_size(&mut self, width: f32, height: f32) {
94 let max_r = width.min(height) / 2.0;
95 self.top_left = self.top_left.clamp(0.0, max_r);
96 self.top_right = self.top_right.clamp(0.0, max_r);
97 self.bottom_left = self.bottom_left.clamp(0.0, max_r);
98 self.bottom_right = self.bottom_right.clamp(0.0, max_r);
99 }
100}
101
102impl From<crate::layout::CornerRadius> for CornerRadii {
103 fn from(value: crate::layout::CornerRadius) -> Self {
104 Self {
105 top_left: value.top_left,
106 top_right: value.top_right,
107 bottom_left: value.bottom_left,
108 bottom_right: value.bottom_right,
109 }
110 }
111}
112
113#[derive(Debug, Clone)]
114pub enum RenderCommandConfig<CustomElementData> {
115 None(),
116 Rectangle(Rectangle),
117 Border(Border),
118 Text(Text),
119 Image(Image),
120 ScissorStart(),
121 ScissorEnd(),
122 Custom(Custom<CustomElementData>),
123 GroupBegin {
126 shader: Option<ShaderConfig>,
128 visual_rotation: Option<VisualRotationConfig>,
130 },
131 GroupEnd,
132}
133
134impl<CustomElementData: Clone + Default + std::fmt::Debug>
135 RenderCommandConfig<CustomElementData>
136{
137 pub(crate) fn from_engine_render_command(value: &engine::InternalRenderCommand<CustomElementData>) -> Self {
138 match value.command_type {
139 engine::RenderCommandType::None => Self::None(),
140 engine::RenderCommandType::Rectangle => {
141 if let engine::InternalRenderData::Rectangle { background_color, corner_radius } = &value.render_data {
142 Self::Rectangle(Rectangle {
143 color: *background_color,
144 corner_radii: (*corner_radius).into(),
145 })
146 } else {
147 Self::None()
148 }
149 }
150 engine::RenderCommandType::Text => {
151 if let engine::InternalRenderData::Text { text, text_color, font_size, letter_spacing, line_height, font_asset } = &value.render_data {
152 Self::Text(Text {
153 text: text.clone(),
154 color: *text_color,
155 font_size: *font_size,
156 letter_spacing: *letter_spacing,
157 line_height: *line_height,
158 font_asset: *font_asset,
159 })
160 } else {
161 Self::None()
162 }
163 }
164 engine::RenderCommandType::Border => {
165 if let engine::InternalRenderData::Border { color, corner_radius, width, position } = &value.render_data {
166 Self::Border(Border {
167 color: *color,
168 corner_radii: (*corner_radius).into(),
169 width: BorderWidth {
170 left: width.left,
171 right: width.right,
172 top: width.top,
173 bottom: width.bottom,
174 between_children: width.between_children,
175 },
176 position: *position,
177 })
178 } else {
179 Self::None()
180 }
181 }
182 engine::RenderCommandType::Image => {
183 if let engine::InternalRenderData::Image { background_color, corner_radius, image_data } = &value.render_data {
184 Self::Image(Image {
185 data: image_data.clone(),
186 corner_radii: (*corner_radius).into(),
187 background_color: *background_color,
188 })
189 } else {
190 Self::None()
191 }
192 }
193 engine::RenderCommandType::ScissorStart => Self::ScissorStart(),
194 engine::RenderCommandType::ScissorEnd => Self::ScissorEnd(),
195 engine::RenderCommandType::GroupBegin => {
196 let shader = value.effects.first().cloned();
199 let visual_rotation = value.visual_rotation;
200 Self::GroupBegin { shader, visual_rotation }
201 }
202 engine::RenderCommandType::GroupEnd => Self::GroupEnd,
203 engine::RenderCommandType::Custom => {
204 if let engine::InternalRenderData::Custom { background_color, corner_radius, custom_data } = &value.render_data {
205 Self::Custom(Custom {
206 background_color: *background_color,
207 corner_radii: (*corner_radius).into(),
208 data: custom_data.clone(),
209 })
210 } else {
211 Self::None()
212 }
213 }
214 }
215 }
216}
217
218#[derive(Debug, Clone)]
220pub struct RenderCommand<CustomElementData> {
221 pub bounding_box: BoundingBox,
223 pub config: RenderCommandConfig<CustomElementData>,
225 pub id: u32,
227 pub z_index: i16,
230 pub effects: Vec<ShaderConfig>,
232 pub shape_rotation: Option<ShapeRotationConfig>,
234}
235
236impl<CustomElementData: Clone + Default + std::fmt::Debug> RenderCommand<CustomElementData> {
237 pub(crate) fn from_engine_render_command(value: &engine::InternalRenderCommand<CustomElementData>) -> Self {
238 let mut config = RenderCommandConfig::from_engine_render_command(value);
239 let bb = value.bounding_box;
240 match &mut config {
241 RenderCommandConfig::Rectangle(r) => r.corner_radii.clamp_to_size(bb.width, bb.height),
242 RenderCommandConfig::Border(b) => b.corner_radii.clamp_to_size(bb.width, bb.height),
243 RenderCommandConfig::Image(i) => i.corner_radii.clamp_to_size(bb.width, bb.height),
244 RenderCommandConfig::Custom(c) => c.corner_radii.clamp_to_size(bb.width, bb.height),
245 _ => {}
246 }
247 Self {
248 id: value.id,
249 z_index: value.z_index,
250 bounding_box: bb,
251 config,
252 effects: value.effects.clone(),
253 shape_rotation: value.shape_rotation,
254 }
255 }
256}