1use crate::{
2 AtlasSet, Bounds, CameraView, DrawOrder, GpuRenderer, GraphicsError, Index,
3 OrderedIndex, OtherError, RectVertex, Texture, Vec2, Vec3, Vec4,
4};
5use cosmic_text::Color;
6
7#[derive(Debug)]
11pub struct Rect {
12 pub pos: Vec3,
14 pub size: Vec2,
16 pub color: Color,
18 pub image: Option<usize>,
20 pub uv: Vec4,
22 pub border_width: f32,
24 pub border_color: Color,
26 pub radius: f32,
28 pub camera_view: CameraView,
30 pub store_id: Index,
32 pub order: DrawOrder,
34 pub bounds: Option<Bounds>,
36 pub changed: bool,
38}
39
40impl Rect {
41 pub fn new(
45 renderer: &mut GpuRenderer,
46 pos: Vec3,
47 size: Vec2,
48 color: Color,
49 order_layer: u32,
50 ) -> Self {
51 let rect_size = bytemuck::bytes_of(&RectVertex::default()).len();
52
53 Self {
54 pos,
55 size,
56 color,
57 image: None,
58 uv: Vec4::default(),
59 border_width: 0.0,
60 border_color: Color::rgba(0, 0, 0, 0),
61 radius: 0.0,
62 camera_view: CameraView::default(),
63 store_id: renderer.new_buffer(rect_size, 0),
64 order: DrawOrder::new(false, Vec3::default(), order_layer),
65 bounds: None,
66 changed: true,
67 }
68 }
69
70 pub fn new_with(
74 renderer: &mut GpuRenderer,
75 image: Option<usize>,
76 pos: Vec3,
77 size: Vec2,
78 uv: Vec4,
79 order_layer: u32,
80 ) -> Self {
81 let rect_size = bytemuck::bytes_of(&RectVertex::default()).len();
82
83 Self {
84 pos,
85 size,
86 color: Color::rgba(255, 255, 255, 255),
87 image,
88 uv,
89 border_width: 0.0,
90 border_color: Color::rgba(0, 0, 0, 0),
91 radius: 0.0,
92 camera_view: CameraView::default(),
93 store_id: renderer.new_buffer(rect_size, 0),
94 order: DrawOrder::new(false, Vec3::default(), order_layer),
95 bounds: None,
96 changed: true,
97 }
98 }
99
100 pub fn unload(self, renderer: &mut GpuRenderer) {
103 renderer.remove_buffer(self.store_id);
104 }
105
106 pub fn set_order_pos(&mut self, order_override: Vec3) -> &mut Self {
110 self.order.set_pos(order_override);
111 self
112 }
113
114 pub fn set_order_layer(&mut self, order_layer: u32) -> &mut Self {
117 self.order.order_layer = order_layer;
118 self
119 }
120
121 pub fn set_order_alpha(&mut self, alpha: bool) -> &mut Self {
125 self.order.alpha = alpha;
126 self
127 }
128
129 pub fn update_bounds(&mut self, bounds: Option<Bounds>) -> &mut Self {
132 self.bounds = bounds;
133 self
134 }
135
136 pub fn set_camera_view(&mut self, camera_view: CameraView) -> &mut Self {
139 self.camera_view = camera_view;
140 self.changed = true;
141 self
142 }
143
144 pub fn set_color(&mut self, color: Color) -> &mut Self {
147 self.color = color;
148 self.order.alpha = self.border_color.a() < 255
149 || self.radius > 0.0
150 || self.color.a() < 255;
151 self.changed = true;
152 self
153 }
154
155 pub fn set_border_color(&mut self, color: Color) -> &mut Self {
158 self.border_color = color;
159 self.order.alpha = self.border_color.a() < 255
160 || self.radius > 0.0
161 || self.color.a() < 255;
162 self.changed = true;
163 self
164 }
165
166 pub fn set_texture(
169 &mut self,
170 renderer: &GpuRenderer,
171 atlas: &mut AtlasSet,
172 path: String,
173 ) -> Result<&mut Self, GraphicsError> {
174 let (id, allocation) =
175 Texture::upload_from_with_alloc(path, atlas, renderer)
176 .ok_or_else(|| OtherError::new("failed to upload image"))?;
177
178 let rect = allocation.rect();
179
180 self.uv = Vec4::new(0.0, 0.0, rect.2 as f32, rect.3 as f32);
181 self.image = Some(id);
182 self.changed = true;
183 Ok(self)
184 }
185
186 pub fn set_container_uv(&mut self, uv: Vec4) -> &mut Self {
189 self.uv = uv;
190 self.changed = true;
191 self
192 }
193
194 pub fn set_pos(&mut self, pos: Vec3) -> &mut Self {
197 self.pos = pos;
198 self.order.set_pos(pos);
199 self.changed = true;
200 self
201 }
202
203 pub fn set_size(&mut self, size: Vec2) -> &mut Self {
206 self.size = size;
207 self.changed = true;
208 self
209 }
210
211 pub fn set_border_width(&mut self, size: f32) -> &mut Self {
214 self.border_width = size;
215 self.changed = true;
216 self
217 }
218
219 pub fn set_radius(&mut self, radius: f32) -> &mut Self {
222 self.radius = radius;
223 self.order.alpha =
224 self.border_color.a() < 255 || radius > 0.0 || self.color.a() < 255;
225 self.changed = true;
226 self
227 }
228
229 pub fn create_quad(
232 &mut self,
233 renderer: &mut GpuRenderer,
234 atlas: &mut AtlasSet,
235 ) {
236 let (uv, layer) = if let Some(id) = self.image {
237 let tex = match atlas.get(id) {
238 Some(tex) => tex,
239 None => return,
240 };
241 let (u, v, width, height) = tex.rect();
242 (
243 [
244 self.uv.x + u as f32,
245 self.uv.y + v as f32,
246 self.uv.z.min(width as f32),
247 self.uv.w.min(height as f32),
248 ],
249 tex.layer as u32,
250 )
251 } else {
252 ([0.0, 0.0, 0.0, 0.0], 0)
253 };
254
255 let instance = RectVertex {
256 pos: self.pos.to_array(),
257 size: self.size.to_array(),
258 border_width: self.border_width,
259 radius: self.radius,
260 uv,
261 layer,
262 color: self.color.0,
263 border_color: self.border_color.0,
264 camera_view: self.camera_view as u32,
265 };
266
267 if let Some(store) = renderer.get_buffer_mut(self.store_id) {
268 let bytes = bytemuck::bytes_of(&instance);
269
270 if bytes.len() != store.store.len() {
271 store.store.resize_with(bytes.len(), || 0);
272 }
273
274 store.store.copy_from_slice(bytes);
275 store.changed = true;
276 }
277 }
278
279 pub fn update(
283 &mut self,
284 renderer: &mut GpuRenderer,
285 atlas: &mut AtlasSet,
286 ) -> OrderedIndex {
287 if self.changed {
289 self.create_quad(renderer, atlas);
290 self.changed = false;
291 }
292
293 OrderedIndex::new_with_bounds(
294 self.order,
295 self.store_id,
296 0,
297 self.bounds,
298 self.camera_view,
299 )
300 }
301
302 pub fn check_mouse_bounds(&self, mouse_pos: Vec2) -> bool {
305 if self.radius > 0.0 {
306 let pos = [self.pos.x, self.pos.y];
307
308 let inner_size = [
309 self.size.x - self.radius * 2.0,
310 self.size.y - self.radius * 2.0,
311 ];
312 let top_left = [pos[0] + self.radius, pos[1] + self.radius];
313 let bottom_right =
314 [top_left[0] + inner_size[0], top_left[1] + inner_size[1]];
315
316 let top_left_distance =
317 [top_left[0] - mouse_pos.x, top_left[1] - mouse_pos.y];
318 let bottom_right_distance =
319 [mouse_pos.x - bottom_right[0], mouse_pos.y - bottom_right[1]];
320
321 let dist = [
322 top_left_distance[0].max(bottom_right_distance[0]).max(0.0),
323 top_left_distance[1].max(bottom_right_distance[1]).max(0.0),
324 ];
325
326 let dist = (dist[0] * dist[0] + dist[1] * dist[1]).sqrt();
327
328 dist < self.radius
329 } else {
330 mouse_pos[0] > self.pos.x
331 && mouse_pos[0] < self.pos.x + self.size.x
332 && mouse_pos[1] > self.pos.y
333 && mouse_pos[1] < self.pos.y + self.size.y
334 }
335 }
336}