1use crate::{
2 brush::Brush,
3 core::{
4 algebra::Vector2,
5 color::Color,
6 math::{self, Rect, TriangleDefinition},
7 },
8 formatted_text::FormattedText,
9 ttf::SharedFont,
10 Thickness,
11};
12use std::{any::Any, ops::Range, sync::Arc};
13
14#[derive(Clone)]
15#[repr(C)]
16pub struct Vertex {
17 pub pos: Vector2<f32>,
18 pub tex_coord: Vector2<f32>,
19 pub color: Color,
20}
21
22impl Vertex {
23 fn new(pos: Vector2<f32>, tex_coord: Vector2<f32>) -> Vertex {
24 Vertex {
25 pos,
26 tex_coord,
27 color: Color::WHITE,
28 }
29 }
30}
31
32pub type Texture = dyn Any + Sync + Send;
33
34#[derive(Debug, Clone)]
35pub struct SharedTexture(pub Arc<Texture>);
36
37impl<T: Any + Sync + Send> From<Arc<T>> for SharedTexture {
38 fn from(arc: Arc<T>) -> Self {
39 SharedTexture(arc)
40 }
41}
42
43impl PartialEq for SharedTexture {
44 fn eq(&self, other: &Self) -> bool {
45 let ptr_a = &*self.0 as *const _ as *const ();
47 let ptr_b = &*other.0 as *const _ as *const ();
48 std::ptr::eq(ptr_a, ptr_b)
50 }
51}
52
53#[derive(Clone)]
54pub enum CommandTexture {
55 None,
56 Texture(SharedTexture),
57 Font(SharedFont),
58}
59
60#[derive(Clone)]
62pub struct ClippingGeometry {
63 pub vertex_buffer: Vec<Vertex>,
64 pub triangle_buffer: Vec<TriangleDefinition>,
65}
66
67impl Draw for ClippingGeometry {
68 #[inline(always)]
69 fn push_vertex(&mut self, pos: Vector2<f32>, tex_coord: Vector2<f32>) {
70 self.vertex_buffer.push(Vertex::new(pos, tex_coord));
71 }
72
73 #[inline(always)]
74 fn push_vertex_raw(&mut self, vertex: Vertex) {
75 self.vertex_buffer.push(vertex);
76 }
77
78 #[inline(always)]
79 fn push_triangle(&mut self, a: u32, b: u32, c: u32) {
80 self.triangle_buffer.push(TriangleDefinition([a, b, c]));
81 }
82
83 #[inline(always)]
84 fn last_vertex_index(&self) -> u32 {
85 self.vertex_buffer.len() as u32
86 }
87}
88
89impl ClippingGeometry {
90 pub fn is_contains_point(&self, pos: Vector2<f32>) -> bool {
91 for triangle in self.triangle_buffer.iter() {
92 if let Some((va, vb, vc)) = self.triangle_points(triangle) {
93 if math::is_point_inside_2d_triangle(pos, va.pos, vb.pos, vc.pos) {
94 return true;
95 }
96 }
97 }
98
99 false
100 }
101
102 pub fn triangle_points(
103 &self,
104 triangle: &TriangleDefinition,
105 ) -> Option<(&Vertex, &Vertex, &Vertex)> {
106 let a = self.vertex_buffer.get(triangle[0] as usize)?;
107 let b = self.vertex_buffer.get(triangle[1] as usize)?;
108 let c = self.vertex_buffer.get(triangle[2] as usize)?;
109 Some((a, b, c))
110 }
111}
112
113#[derive(Clone)]
114pub struct Command {
115 pub clip_bounds: Rect<f32>,
117 pub bounds: Rect<f32>,
119 pub brush: Brush,
121 pub texture: CommandTexture,
122 pub triangles: Range<usize>,
123 pub opacity: f32,
124 pub clipping_geometry: Option<ClippingGeometry>,
126}
127
128pub trait Draw {
129 fn push_vertex(&mut self, pos: Vector2<f32>, tex_coord: Vector2<f32>);
130
131 fn push_vertex_raw(&mut self, vertex: Vertex);
132
133 fn push_triangle(&mut self, a: u32, b: u32, c: u32);
134
135 fn last_vertex_index(&self) -> u32;
136
137 fn push_triangle_multicolor(&mut self, vertices: [(Vector2<f32>, Color); 3]) {
138 let index = self.last_vertex_index();
139 for &(pos, color) in &vertices {
140 self.push_vertex_raw(Vertex {
141 pos,
142 tex_coord: Vector2::new(0.0, 0.0),
143 color,
144 });
145 }
146
147 self.push_triangle(index, index + 1, index + 2);
148 }
149
150 fn push_triangle_filled(&mut self, vertices: [Vector2<f32>; 3]) {
151 let index = self.last_vertex_index();
152
153 for &pos in &vertices {
154 self.push_vertex(pos, Default::default());
155 }
156
157 self.push_triangle(index, index + 1, index + 2);
158 }
159
160 fn push_line(&mut self, a: Vector2<f32>, b: Vector2<f32>, thickness: f32) {
161 let index = self.last_vertex_index();
162 let perp = get_line_thickness_vector(a, b, thickness);
163 self.push_vertex(a - perp, Vector2::new(0.0, 0.0));
164 self.push_vertex(b - perp, Vector2::new(1.0, 0.0));
165 self.push_vertex(a + perp, Vector2::new(1.0, 1.0));
166 self.push_vertex(b + perp, Vector2::new(0.0, 1.0));
167
168 self.push_triangle(index, index + 1, index + 2);
169 self.push_triangle(index + 2, index + 1, index + 3);
170 }
171
172 fn push_rect(&mut self, rect: &Rect<f32>, thickness: f32) {
173 let offset = thickness * 0.5;
174
175 let left_top = Vector2::new(rect.x() + offset, rect.y() + thickness);
176 let right_top = Vector2::new(rect.x() + rect.w() - offset, rect.y() + thickness);
177 let right_bottom = Vector2::new(
178 rect.x() + rect.w() - offset,
179 rect.y() + rect.h() - thickness,
180 );
181 let left_bottom = Vector2::new(rect.x() + offset, rect.y() + rect.h() - thickness);
182 let left_top_off = Vector2::new(rect.x(), rect.y() + offset);
183 let right_top_off = Vector2::new(rect.x() + rect.w(), rect.y() + offset);
184 let right_bottom_off = Vector2::new(rect.x() + rect.w(), rect.y() + rect.h() - offset);
185 let left_bottom_off = Vector2::new(rect.x(), rect.y() + rect.h() - offset);
186
187 self.push_line(left_top_off, right_top_off, thickness);
189 self.push_line(right_bottom_off, left_bottom_off, thickness);
190
191 self.push_line(right_top, right_bottom, thickness);
193 self.push_line(left_bottom, left_top, thickness);
194 }
195
196 fn push_rect_vary(&mut self, rect: &Rect<f32>, thickness: Thickness) {
197 let left_top = Vector2::new(rect.x() + thickness.left * 0.5, rect.y() + thickness.top);
198 let right_top = Vector2::new(
199 rect.x() + rect.w() - thickness.right * 0.5,
200 rect.y() + thickness.top,
201 );
202 let right_bottom = Vector2::new(
203 rect.x() + rect.w() - thickness.right * 0.5,
204 rect.y() + rect.h() - thickness.bottom,
205 );
206 let left_bottom = Vector2::new(
207 rect.x() + thickness.left * 0.5,
208 rect.y() + rect.h() - thickness.bottom,
209 );
210 let left_top_off = Vector2::new(rect.x(), rect.y() + thickness.top * 0.5);
211 let right_top_off = Vector2::new(rect.x() + rect.w(), rect.y() + thickness.top * 0.5);
212 let right_bottom_off = Vector2::new(
213 rect.x() + rect.w(),
214 rect.y() + rect.h() - thickness.bottom * 0.5,
215 );
216 let left_bottom_off = Vector2::new(rect.x(), rect.y() + rect.h() - thickness.bottom * 0.5);
217
218 self.push_line(left_top_off, right_top_off, thickness.top);
220 self.push_line(right_bottom_off, left_bottom_off, thickness.bottom);
221
222 self.push_line(right_top, right_bottom, thickness.right);
224 self.push_line(left_bottom, left_top, thickness.left);
225 }
226
227 fn push_rect_filled(&mut self, rect: &Rect<f32>, tex_coords: Option<&[Vector2<f32>; 4]>) {
228 let index = self.last_vertex_index();
229 self.push_vertex(
230 Vector2::new(rect.x(), rect.y()),
231 tex_coords.map_or(Vector2::new(0.0, 0.0), |t| t[0]),
232 );
233 self.push_vertex(
234 Vector2::new(rect.x() + rect.w(), rect.y()),
235 tex_coords.map_or(Vector2::new(1.0, 0.0), |t| t[1]),
236 );
237 self.push_vertex(
238 Vector2::new(rect.x() + rect.w(), rect.y() + rect.h()),
239 tex_coords.map_or(Vector2::new(1.0, 1.0), |t| t[2]),
240 );
241 self.push_vertex(
242 Vector2::new(rect.x(), rect.y() + rect.h()),
243 tex_coords.map_or(Vector2::new(0.0, 1.0), |t| t[3]),
244 );
245
246 self.push_triangle(index, index + 1, index + 2);
247 self.push_triangle(index, index + 2, index + 3);
248 }
249
250 fn push_rect_multicolor(&mut self, rect: &Rect<f32>, colors: [Color; 4]) {
251 let index = self.last_vertex_index();
252 self.push_vertex_raw(Vertex {
253 pos: rect.left_top_corner(),
254 tex_coord: Vector2::new(0.0, 0.0),
255 color: colors[0],
256 });
257 self.push_vertex_raw(Vertex {
258 pos: rect.right_top_corner(),
259 tex_coord: Vector2::new(1.0, 0.0),
260 color: colors[1],
261 });
262 self.push_vertex_raw(Vertex {
263 pos: rect.right_bottom_corner(),
264 tex_coord: Vector2::new(1.0, 1.0),
265 color: colors[2],
266 });
267 self.push_vertex_raw(Vertex {
268 pos: rect.left_bottom_corner(),
269 tex_coord: Vector2::new(0.0, 1.0),
270 color: colors[3],
271 });
272
273 self.push_triangle(index, index + 1, index + 2);
274 self.push_triangle(index, index + 2, index + 3);
275 }
276
277 fn push_circle(&mut self, origin: Vector2<f32>, radius: f32, segments: usize, color: Color) {
278 if segments >= 3 {
279 let center_index = self.last_vertex_index();
280
281 self.push_vertex_raw(Vertex {
282 pos: origin,
283 tex_coord: Vector2::default(),
284 color,
285 });
286
287 let two_pi = 2.0 * std::f32::consts::PI;
288 let delta_angle = two_pi / (segments as f32);
289 let mut angle: f32 = 0.0;
290 for _ in 0..segments {
291 let x = origin.x + radius * angle.cos();
292 let y = origin.y + radius * angle.sin();
293 self.push_vertex_raw(Vertex {
294 pos: Vector2::new(x, y),
295 tex_coord: Vector2::default(),
296 color,
297 });
298 angle += delta_angle;
299 }
300
301 let first_vertex = center_index + 1;
302 for segment in 0..segments {
303 self.push_triangle(
304 center_index,
305 first_vertex + segment as u32,
306 first_vertex + (segment as u32 + 1) % segments as u32,
307 );
308 }
309 }
310 }
311}
312
313pub struct DrawingContext {
314 vertex_buffer: Vec<Vertex>,
315 triangle_buffer: Vec<TriangleDefinition>,
316 command_buffer: Vec<Command>,
317 opacity_stack: Vec<f32>,
318 triangles_to_commit: usize,
319}
320
321fn get_line_thickness_vector(a: Vector2<f32>, b: Vector2<f32>, thickness: f32) -> Vector2<f32> {
322 if let Some(dir) = (b - a).try_normalize(f32::EPSILON) {
323 Vector2::new(dir.y, -dir.x).scale(thickness * 0.5)
324 } else {
325 Vector2::default()
326 }
327}
328
329impl Default for DrawingContext {
330 fn default() -> Self {
331 Self::new()
332 }
333}
334
335impl Draw for DrawingContext {
336 #[inline(always)]
337 fn push_vertex(&mut self, pos: Vector2<f32>, tex_coord: Vector2<f32>) {
338 self.vertex_buffer.push(Vertex::new(pos, tex_coord));
339 }
340
341 #[inline(always)]
342 fn push_vertex_raw(&mut self, vertex: Vertex) {
343 self.vertex_buffer.push(vertex);
344 }
345
346 #[inline(always)]
347 fn push_triangle(&mut self, a: u32, b: u32, c: u32) {
348 self.triangle_buffer.push(TriangleDefinition([a, b, c]));
349 self.triangles_to_commit += 1;
350 }
351
352 #[inline(always)]
353 fn last_vertex_index(&self) -> u32 {
354 self.vertex_buffer.len() as u32
355 }
356}
357
358impl DrawingContext {
359 pub fn new() -> DrawingContext {
360 DrawingContext {
361 vertex_buffer: Vec::new(),
362 triangle_buffer: Vec::new(),
363 command_buffer: Vec::new(),
364 triangles_to_commit: 0,
365 opacity_stack: vec![1.0],
366 }
367 }
368
369 #[inline]
370 pub fn clear(&mut self) {
371 self.vertex_buffer.clear();
372 self.triangle_buffer.clear();
373 self.command_buffer.clear();
374 self.opacity_stack.clear();
375 self.opacity_stack.push(1.0);
376 self.triangles_to_commit = 0;
377 }
378
379 #[inline]
380 pub fn get_vertices(&self) -> &[Vertex] {
381 self.vertex_buffer.as_slice()
382 }
383
384 #[inline]
385 pub fn get_triangles(&self) -> &[TriangleDefinition] {
386 self.triangle_buffer.as_slice()
387 }
388
389 #[inline]
390 pub fn get_commands(&self) -> &Vec<Command> {
391 &self.command_buffer
392 }
393
394 pub fn push_opacity(&mut self, opacity: f32) {
395 self.opacity_stack.push(opacity);
396 }
397
398 pub fn pop_opacity(&mut self) {
399 self.opacity_stack.pop().unwrap();
400 }
401
402 pub fn triangle_points(
403 &self,
404 triangle: &TriangleDefinition,
405 ) -> Option<(&Vertex, &Vertex, &Vertex)> {
406 let a = self.vertex_buffer.get(triangle[0] as usize)?;
407 let b = self.vertex_buffer.get(triangle[1] as usize)?;
408 let c = self.vertex_buffer.get(triangle[2] as usize)?;
409 Some((a, b, c))
410 }
411
412 pub fn is_command_contains_point(&self, command: &Command, pos: Vector2<f32>) -> bool {
413 for i in command.triangles.clone() {
414 if let Some(triangle) = self.triangle_buffer.get(i) {
415 if let Some((va, vb, vc)) = self.triangle_points(triangle) {
416 if math::is_point_inside_2d_triangle(pos, va.pos, vb.pos, vc.pos) {
417 return true;
418 }
419 }
420 }
421 }
422
423 false
424 }
425
426 fn pending_range(&self) -> Range<usize> {
427 if self.triangle_buffer.is_empty() {
428 0..self.triangles_to_commit
429 } else {
430 (self.triangle_buffer.len() - self.triangles_to_commit)..self.triangle_buffer.len()
431 }
432 }
433
434 fn bounds_of(&self, range: Range<usize>) -> Rect<f32> {
435 let mut bounds = Rect::new(f32::MAX, f32::MAX, 0.0, 0.0);
436 for i in range {
437 for &k in self.triangle_buffer[i].as_ref() {
438 bounds.push(self.vertex_buffer[k as usize].pos);
439 }
440 }
441 bounds
442 }
443
444 pub fn commit(
445 &mut self,
446 clip_bounds: Rect<f32>,
447 brush: Brush,
448 texture: CommandTexture,
449 clipping_geometry: Option<ClippingGeometry>,
450 ) {
451 if self.triangles_to_commit > 0 {
452 let triangles = self.pending_range();
453 let bounds = self.bounds_of(triangles.clone());
454
455 let opacity = *self.opacity_stack.last().unwrap();
456 self.command_buffer.push(Command {
457 clip_bounds,
458 bounds,
459 brush,
460 texture,
461 triangles,
462 opacity,
463 clipping_geometry,
464 });
465 self.triangles_to_commit = 0;
466 }
467 }
468
469 pub fn draw_text(
470 &mut self,
471 clip_bounds: Rect<f32>,
472 position: Vector2<f32>,
473 formatted_text: &FormattedText,
474 ) {
475 let font = formatted_text.get_font();
476
477 for element in formatted_text.get_glyphs() {
478 let bounds = element.get_bounds();
479
480 let final_bounds = Rect::new(
481 position.x + bounds.x(),
482 position.y + bounds.y(),
483 bounds.w(),
484 bounds.h(),
485 );
486
487 self.push_rect_filled(&final_bounds, Some(element.get_tex_coords()));
488 }
489
490 self.commit(
491 clip_bounds,
492 formatted_text.brush(),
493 CommandTexture::Font(font),
494 None,
495 )
496 }
497}