est_render/gpu/command/
drawing.rs

1//! Drawing, an intermediate mode drawing for some 2D primitives.
2
3use std::{cell::RefCell, collections::HashMap};
4use super::RenderPass;
5
6use crate::{
7    font::{Font, FontManager}, math::{Color, Point2, RectF, Vector2, Vector3, Vertex}, utils::ArcRef
8};
9
10use super::{
11    super::{
12        GPUInner,
13        texture::{
14            atlas::TextureAtlas,
15            Texture, 
16            TextureBuilder, 
17            TextureUsage, 
18            TextureSampler,
19            TextureFormat
20        },
21        shader::{GraphicsShader, GraphicsShaderBuilder},
22    },
23};
24
25#[derive(Clone, Debug)]
26pub(crate) struct DrawingGlobalState {
27    pub texture: Texture,
28    pub shader: GraphicsShader,
29    pub font_manager: FontManager,
30    pub font_textures: HashMap<String, Texture>,
31}
32
33impl DrawingGlobalState {
34    pub fn new(gpu_inner: &ArcRef<GPUInner>) -> Option<Self> {
35        let default_texture = TextureBuilder::new(ArcRef::clone(gpu_inner))
36            .set_raw_image(&[255u8, 255, 255, 255], Point2::new(1, 1), TextureFormat::Bgra8Unorm)
37            .set_usage(TextureUsage::Sampler)
38            .build()
39            .ok()?;
40
41        let default_shader = GraphicsShaderBuilder::new(ArcRef::clone(gpu_inner))
42            .set_source(include_str!("./resources/drawing_shader.wgsl"))
43            .build()
44            .ok()?;
45
46        let font_manager = FontManager::new();
47
48        Some(Self {
49            texture: default_texture,
50            shader: default_shader,
51            font_manager,
52            font_textures: HashMap::new(),
53        })
54    }
55}
56
57pub(crate) struct DrawingContextInner {
58    pass: RenderPass,
59    drawing_global_state: ArcRef<DrawingGlobalState>,
60
61    vertices: Vec<Vertex>,
62    indices: Vec<u16>,
63
64    texture: Option<(Texture, TextureSampler)>,
65    texture_uv: Option<RectF>,
66    texture_atlas_uv: Option<RectF>,
67    shader: Option<GraphicsShader>,
68    scissor: Option<RectF>,
69    viewport: Option<RectF>,
70    current_queue: Option<DrawingQueue>,
71    queue: Vec<DrawingQueue>,
72
73    current_font: Option<Font>,
74    current_font_texture: Option<Texture>,
75}
76
77impl DrawingContextInner {
78    pub fn get_absolute_uv(&self) -> RectF {
79        fn remap_uv(rect1: RectF, rect2: RectF) -> RectF {
80            RectF {
81                x: rect2.x + (rect2.w - rect2.x) * rect1.x,
82                y: rect2.y + (rect2.h - rect2.y) * rect1.y,
83                w: rect2.x + (rect2.w - rect2.x) * rect1.w,
84                h: rect2.y + (rect2.h - rect2.y) * rect1.h,
85            }
86        }
87
88        fn resolve_uv(uv1: Option<RectF>, uv2: Option<RectF>) -> RectF {
89            match (uv1, uv2) {
90                (Some(r1), Some(r2)) => remap_uv(r1, r2),
91                (Some(r1), None) => r1,
92                (None, Some(r2)) => r2,
93                (None, None) => RectF::new(0.0, 0.0, 1.0, 1.0),
94            }
95        }
96
97        resolve_uv(self.texture_uv.clone(), self.texture_atlas_uv.clone())
98    }
99
100    pub fn push_geometry(
101        &mut self,
102        vertices: &[Vertex],
103        indices: &[u16],
104        has_image: bool,
105    ) {
106        if vertices.is_empty() || indices.is_empty() {
107            return;
108        }
109
110        let base_index = self.vertices.len() as u16;
111        let indices: Vec<u16> = indices.iter().map(|i| i + base_index).collect();
112        self.push_queue(indices.len() as u32, has_image);
113
114        #[cfg(any(debug_assertions, feature = "enable-release-validation"))]
115        {
116            for vertex in vertices {
117                if vertex.position.z != 0.0 {
118                    panic!("DrawingContext only supports 2D rendering with z = 0.0");
119                }
120
121                if vertex.texcoord.x < 0.0
122                    || vertex.texcoord.y < 0.0
123                    || vertex.texcoord.x > 1.0
124                    || vertex.texcoord.y > 1.0
125                {
126                    panic!("Texture coordinates must be in the range [0, 1]");
127                }
128            }
129        }
130
131        self.vertices.extend_from_slice(&vertices);
132        self.indices.extend_from_slice(&indices);
133    }
134
135    pub fn push_queue(
136        &mut self,
137        count: u32,
138        has_image: bool,
139    ) {
140        let mut push_new_queue = false;
141
142        if self.current_queue.is_some() {
143            let ref_queue = self.current_queue.as_ref().unwrap();
144
145            // Check if current queue has the same texture, if not push the queue
146            let current_texture = if has_image { &self.texture } else { &None };
147
148            let texture_changed = match (&ref_queue.texture, current_texture) {
149                (None, None) => false,
150                (Some(_), None) | (None, Some(_)) => true,
151                (
152                    Some((old_texture, old_sampler)),
153                    Some((new_texture, new_sampler)),
154                ) => {
155                    old_texture != new_texture
156                        || old_sampler != new_sampler
157                }
158            };
159
160            if texture_changed {
161                push_new_queue = true;
162            }
163
164            // Check if current queue has the same scissor, if not push the queue
165            if ref_queue.scissors != self.scissor {
166                push_new_queue = true;
167            }
168
169            // Check if current queue has the same viewport, if not push the queue
170            if ref_queue.viewport != self.viewport {
171                push_new_queue = true;
172            }
173
174            // check if current queue has the same shader, if not push the queue
175            if ref_queue.shader != self.shader {
176                push_new_queue = true;
177            }
178        } else {
179            push_new_queue = true;
180        }
181
182        // Figure a way to push queue with correct start, and count
183        if push_new_queue {
184            if let Some(queue) = self.current_queue.take() {
185                self.queue.push(queue);
186            }
187
188            self.current_queue = Some(DrawingQueue {
189                texture: self.texture.clone(),
190                shader: None,
191                scissors: self.scissor.clone(),
192                viewport: self.viewport.clone(),
193                start_index: self.indices.len() as u32,
194                start_vertex: 0, // TODO: Fix this
195                count,
196            });
197        } else {
198            let queue = self.current_queue.as_mut().unwrap();
199            queue.count += count;
200        }
201    }
202
203    pub fn load_font(&mut self, font_path: &str, range: Option<&[(u32, u32)]>, size: f32) {
204        let mut state = self.drawing_global_state.borrow_mut();
205        if let Some(font) = state.font_manager.load_font(font_path, range, size) {
206            if !state.font_textures.contains_key(font_path) {
207                let texture = font.create_texture_inner(&self.pass.graphics)
208                    .expect("Failed to create font texture");
209
210                state.font_textures.insert(font_path.to_string(), texture);
211            }
212
213            self.current_font = Some(font);
214            self.current_font_texture = state.font_textures.get(font_path).cloned();
215        } else {
216            #[cfg(any(debug_assertions, feature = "enable-release-validation"))]
217            {
218                crate::dbg_log!("Failed to load font: {}", font_path);
219            }
220        }
221    }
222
223    pub fn set_font(&mut self, font: &Font) {
224        let name = {
225            let font_inner = font.inner.borrow();
226            font_inner.info.path.clone().into_os_string().into_string()
227                .ok()
228        };
229
230        if name.is_none() {
231            #[cfg(any(debug_assertions, feature = "enable-release-validation"))]
232            {
233                crate::dbg_log!("Font path is None, cannot set font");
234            }
235            return;
236        }
237
238        let name = name.unwrap();
239
240        let mut state = self.drawing_global_state.borrow_mut();
241        if !state.font_textures.contains_key(&name) {
242            let texture = font.create_texture_inner(&self.pass.graphics)
243                .expect("Failed to create font texture");
244
245            state.font_textures.insert(name.to_string(), texture);
246        }
247
248        self.current_font = Some(font.clone());
249        self.current_font_texture = state.font_textures.get(&name).cloned();
250    }
251}
252
253pub(crate) struct DrawingQueue {
254    pub texture: Option<(Texture, TextureSampler)>,
255    pub shader: Option<GraphicsShader>,
256
257    pub scissors: Option<RectF>,
258    pub viewport: Option<RectF>,
259
260    pub start_index: u32,
261    pub start_vertex: u32,
262    pub count: u32,
263}
264
265/// DrawingContext is an intermediate mode for drawing 2D primitives.
266///
267/// It provides methods to draw rectangles, lines, triangles, circles, and images with various options for colors and textures.
268pub struct DrawingContext {
269    pub(crate) inner: ArcRef<DrawingContextInner>,
270
271    pub(crate) vertex_cache: Vec<Vertex>,
272    pub(crate) index_cache: Vec<u16>,
273}
274
275impl DrawingContext {
276    pub(crate) fn new(pass: RenderPass) -> Option<Self> {
277        if pass.graphics.borrow().drawing_state.is_none() {
278            let state = DrawingGlobalState::new(&pass.graphics)?;
279
280            let mut gpu_inner = pass.graphics.borrow_mut();
281            gpu_inner.drawing_state = Some(ArcRef::new(state));
282        }
283
284        let drawing_state = ArcRef::clone(
285            &pass.graphics.borrow().drawing_state.as_ref().unwrap()
286        );
287
288        let inner = DrawingContextInner {
289            pass: pass,
290            drawing_global_state: drawing_state,
291
292            vertices: Vec::new(),
293            indices: Vec::new(),
294            texture: None,
295            texture_uv: None,
296            texture_atlas_uv: None,
297            shader: None,
298            scissor: None,
299            viewport: None,
300            current_queue: None,
301            queue: Vec::new(),
302            
303            current_font: None,
304            current_font_texture: None,
305        };
306
307        Some(DrawingContext {
308            inner: ArcRef::new(inner),
309
310            vertex_cache: Vec::new(),
311            index_cache: Vec::new(),
312        })
313    }
314
315    fn construct_line(a: Vector2, b: Vector2, thickness: f32) -> Option<([Vector2; 4], [u16; 6])> {
316        let dir = b - a;
317        let len = dir.length();
318        if len == 0.0 {
319            return None;
320        }
321
322        let dir = dir / len;
323        let perp = Vector2::new(-dir.y, dir.x) * (thickness * 0.5);
324
325        let vertices = [a + perp, b + perp, b - perp, a - perp];
326
327        let indices = [0, 1, 2, 0, 2, 3];
328
329        Some((vertices, indices))
330    }
331
332    #[allow(dead_code)]
333    fn construct_quad(pos: Vector2, size: Vector2) -> ([Vector2; 4], [u16; 6]) {
334        let vertices = [
335            Vector2::new(pos.x, pos.y),
336            Vector2::new(pos.x + size.x, pos.y),
337            Vector2::new(pos.x + size.x, pos.y + size.y),
338            Vector2::new(pos.x, pos.y + size.y),
339        ];
340
341        let indices = [0, 1, 2, 0, 2, 3];
342
343        (vertices, indices)
344    }
345
346    #[allow(unused)]
347    pub fn load_font(&mut self, font_path: &str, range: Option<&[(u32, u32)]>, size: f32) {
348        let mut inner = self.inner.borrow_mut();
349        inner.load_font(font_path, range, size);
350    }
351
352    pub fn set_font(&mut self, font: &Font) {
353        let mut inner = self.inner.borrow_mut();
354        inner.set_font(font);
355    }
356
357    #[allow(unused)]
358    pub fn draw_text(&mut self, text: &str, pos: Vector2, color: Color) {
359        let mut inner = self.inner.borrow_mut();
360        if inner.current_font.is_none() {
361            inner.load_font("Arial", None, 16.0);
362        }
363
364        vec_clear(&mut self.vertex_cache);
365        vec_clear(&mut self.index_cache);
366
367        let font = inner.current_font.as_ref().unwrap();
368        let texture_size = font.texture_size();
369        let line_height = font.line_height();
370        let ascender = font.ascender();
371        let space_width = font.space_width();
372
373        // Calculate the minimum Y offset for the text
374        let mut pen_y = 0.0;
375        let mut min_y = f32::MAX;
376        for c in text.chars() {
377            let codepoint = c as u32;
378            if codepoint == 0 {
379                continue;
380            }
381
382            if codepoint == '\n' as u32 {
383                pen_y += line_height;
384                continue;
385            }
386
387            if let Ok(glyph) = font.get_glyph(codepoint) {
388                min_y = f32::min(min_y, pen_y + ascender - (glyph.bearing_y + glyph.height));
389            }
390        }
391
392        let mut pen = pos;
393        for c in text.chars() {
394            let codepoint = c as u32;
395            if codepoint == 0 {
396                continue;
397            }
398
399            if codepoint == '\n' as u32 {
400                pen.x = pos.x;
401                pen.y += line_height;
402                continue;
403            }
404
405            if codepoint == ' ' as u32 {
406                pen.x += space_width;
407                continue;
408            }
409
410            if let Ok(glyph) = font.get_glyph(codepoint) {
411                let x0 = pen.x + glyph.bearing_x;
412                let y0 = pen.y + ascender - (glyph.bearing_y + glyph.height) - min_y;
413                let x1 = x0 + glyph.width;
414                let y1 = y0 + glyph.height;
415
416                let uv_x0 = glyph.atlas_start_offset.x as f32 / texture_size.x as f32;
417                let uv_y0 = glyph.atlas_start_offset.y as f32 / texture_size.y as f32;
418                let uv_x1 = (glyph.atlas_start_offset.x + glyph.width) as f32 / texture_size.x as f32;
419                let uv_y1 = (glyph.atlas_start_offset.y + glyph.height) as f32 / texture_size.y as f32;
420
421                let vertices = [
422                    Vertex::new(Vector3::new(x0, y0, 0.0), color, Vector2::new(uv_x0, uv_y0)),
423                    Vertex::new(Vector3::new(x1, y0, 0.0), color, Vector2::new(uv_x1, uv_y0)),
424                    Vertex::new(Vector3::new(x1, y1, 0.0), color, Vector2::new(uv_x1, uv_y1)),
425                    Vertex::new(Vector3::new(x0, y1, 0.0), color, Vector2::new(uv_x0, uv_y1)),
426                ];
427
428                let base_index = self.vertex_cache.len() as u16;
429                let indices = [
430                    base_index + 0,
431                    base_index + 1,
432                    base_index + 2,
433                    base_index + 0,
434                    base_index + 2,
435                    base_index + 3,
436                ];
437
438                self.vertex_cache.extend_from_slice(&vertices);
439                self.index_cache.extend_from_slice(&indices);
440
441                pen.x += glyph.advance_x;
442            }
443        }
444
445        if self.index_cache.is_empty() {
446            return;
447        }
448
449        let mut all_vertices = &self.vertex_cache;
450        let mut all_indices = &self.index_cache;
451
452        let current_texture = inner.texture.clone();
453        let font_texture = inner.current_font_texture.clone();
454        inner.texture = Some((
455            font_texture.unwrap(),
456            TextureSampler::DEFAULT,
457        ));
458
459        inner.push_geometry(&all_vertices, &all_indices, true);
460
461        inner.texture = current_texture;
462    }
463
464    /// Draw hollow rectangle with a specified position, size, thickness, and color.
465    pub fn draw_rect(&mut self, pos: Vector2, size: Vector2, thickness: f32, color: Color) {
466        let corners = [
467            pos,
468            pos + Vector2::new(size.x, 0.0),
469            pos + size,
470            pos + Vector2::new(0.0, size.y),
471        ];
472
473        let all_vertices = &mut self.vertex_cache;
474        let all_indices = &mut self.index_cache;
475        let mut index_offset = 0u16;
476
477        vec_clear(all_vertices);
478        vec_clear(all_indices);
479
480        for i in 0..4 {
481            let a = corners[i];
482            let b = corners[(i + 1) % 4];
483            let line = Self::construct_line(a, b, thickness);
484            if line.is_none() {
485                continue;
486            }
487
488            let (vertices, mut indices) = line.unwrap();
489            let vertices = vertices
490                .iter()
491                .map(|v| {
492                    Vertex::new(
493                        Vector3::new(v.x, v.y, 0.0),
494                        color,
495                        Vector2::ZERO,
496                    )
497                })
498                .collect::<Vec<_>>();
499
500            indices.iter_mut().for_each(|idx| *idx += index_offset);
501            index_offset += vertices.len() as u16;
502
503            all_vertices.extend(vertices);
504            all_indices.extend(indices);
505        }
506
507        self.inner.borrow_mut()
508            .push_geometry(&all_vertices, &all_indices, false);
509    }
510
511    /// Draw line between two points with a specified thickness and color.
512    pub fn draw_line(&mut self, a: Vector2, b: Vector2, thickness: f32, color: Color) {
513        let line = Self::construct_line(a, b, thickness);
514        if line.is_none() {
515            return;
516        }
517
518        let (vertices, indices) = line.unwrap();
519        let vertices = vertices
520            .iter()
521            .map(|v| {
522                Vertex::new(
523                    Vector3::new(v.x, v.y, 0.0),
524                    color,
525                    Vector2::ZERO,
526                )
527            })
528            .collect::<Vec<_>>();
529
530        self.inner.borrow_mut()
531            .push_geometry(&vertices, &indices, false);
532    }
533
534    /// Draw rectangle filled with a specified position, size, and color.
535    pub fn draw_rect_filled(&mut self, pos: Vector2, size: Vector2, color: Color) {
536        let vertices = [
537            Vertex::new(
538                Vector3::new(pos.x, pos.y, 0.0),
539                color,
540                Vector2::ZERO,
541            ),
542            Vertex::new(
543                Vector3::new(pos.x + size.x, pos.y, 0.0),
544                color,
545                Vector2::ZERO,
546            ),
547            Vertex::new(
548                Vector3::new(pos.x + size.x, pos.y + size.y, 0.0),
549                color,
550                Vector2::ZERO,
551            ),
552            Vertex::new(
553                Vector3::new(pos.x, pos.y + size.y, 0.0),
554                color,
555                Vector2::ZERO,
556            ),
557        ];
558
559        let indices = [0, 1, 2, 0, 2, 3];
560
561        self.inner.borrow_mut()
562            .push_geometry(&vertices, &indices, false);
563    }
564
565    /// Draw rectangle filled with specified colors for each corner.
566    pub fn draw_rect_filled_colors(
567        &mut self,
568        pos: Vector2,
569        size: Vector2,
570        color_tl: Color,
571        color_tr: Color,
572        color_br: Color,
573        color_bl: Color,
574    ) {
575        let vertices = [
576            Vertex::new(
577                Vector3::new(pos.x, pos.y, 0.0),
578                color_tl.into_srgb(),
579                Vector2::ZERO,
580            ),
581            Vertex::new(
582                Vector3::new(pos.x + size.x, pos.y, 0.0),
583                color_tr.into_srgb(),
584                Vector2::ZERO,
585            ),
586            Vertex::new(
587                Vector3::new(pos.x + size.x, pos.y + size.y, 0.0),
588                color_br.into_srgb(),
589                Vector2::ZERO,
590            ),
591            Vertex::new(
592                Vector3::new(pos.x, pos.y + size.y, 0.0),
593                color_bl.into_srgb(),
594                Vector2::ZERO,
595            ),
596        ];
597
598        let indices = [
599            0, 1, 2, // First triangle
600            0, 2, 3, // Second triangle
601        ];
602
603        self.inner.borrow_mut()
604            .push_geometry(&vertices, &indices, false);
605    }
606
607    /// Draw triangle with specified vertices, thickness, and color.
608    pub fn draw_triangle(
609        &mut self,
610        a: Vector2,
611        b: Vector2,
612        c: Vector2,
613        thickness: f32,
614        color: Color,
615    ) {
616        let points = [
617            Vector2::new(a.x, a.y),
618            Vector2::new(b.x, b.y),
619            Vector2::new(c.x, c.y),
620        ];
621
622        let all_vertices = &mut self.vertex_cache;
623        let all_indices = &mut self.index_cache;
624
625        vec_clear(all_vertices);
626        vec_clear(all_indices);
627
628        let mut index_offset = 0u16;
629        for i in 0..3 {
630            let a = points[i];
631            let b = points[(i + 1) % 3];
632
633            let line = Self::construct_line(a, b, thickness);
634            if line.is_none() {
635                continue;
636            }
637
638            let (vertices, mut indices) = line.unwrap();
639            let vertices = vertices
640                .iter()
641                .map(|v| Vertex::new(Vector3::new(v.x, v.y, 0.0), color, Vector2::ZERO))
642                .collect::<Vec<_>>();
643
644            indices.iter_mut().for_each(|idx| *idx += index_offset);
645            index_offset += vertices.len() as u16;
646
647            all_vertices.extend(vertices);
648            all_indices.extend(indices);
649        }
650
651        if all_indices.is_empty() {
652            return;
653        }
654
655        self.inner.borrow_mut()
656            .push_geometry(&all_vertices, &all_indices, false);
657    }
658
659    /// Draw triangle filled with specified vertices and color.
660    pub fn draw_triangle_filled(&mut self, a: Vector2, b: Vector2, c: Vector2, color: Color) {
661        let vertices = [
662            Vertex::new(Vector3::new(a.x, a.y, 0.0), color, Vector2::ZERO),
663            Vertex::new(Vector3::new(b.x, b.y, 0.0), color, Vector2::ZERO),
664            Vertex::new(Vector3::new(c.x, c.y, 0.0), color, Vector2::ZERO),
665        ];
666
667        let indices = [0, 1, 2];
668
669        self.inner.borrow_mut()
670            .push_geometry(&vertices, &indices, false);
671    }
672
673    /// Draw circle with a specified center, radius, number of segments, thickness, and color.
674    pub fn draw_circle(
675        &mut self,
676        center: Vector2,
677        radius: f32,
678        segments: u32,
679        thickness: f32,
680        color: Color,
681    ) {
682        if segments < 3 {
683            return;
684        }
685
686        let angle_step = std::f32::consts::PI * 2.0 / segments as f32;
687
688        let mut vertices = Vec::with_capacity(segments as usize * 2);
689        let mut indices = Vec::with_capacity(segments as usize * 6);
690
691        for i in 0..segments {
692            let angle_a = i as f32 * angle_step;
693            let angle_b = (i + 1) as f32 * angle_step;
694
695            let a = Vector2::new(
696                center.x + radius * angle_a.cos(),
697                center.y + radius * angle_a.sin(),
698            );
699            let b = Vector2::new(
700                center.x + radius * angle_b.cos(),
701                center.y + radius * angle_b.sin(),
702            );
703
704            let line = Self::construct_line(a, b, thickness);
705            if line.is_none() {
706                continue;
707            }
708
709            let (line_vertices, line_indices) = line.unwrap();
710
711            let base_index = vertices.len() as u16;
712            let line_vertices: Vec<Vertex> = line_vertices
713                .iter()
714                .map(|v| Vertex::new(Vector3::new(v.x, v.y, 0.0), color, Vector2::ZERO))
715                .collect();
716
717            vertices.extend(line_vertices);
718            indices.extend(line_indices.into_iter().map(|i| i + base_index));
719        }
720
721        if indices.is_empty() {
722            return;
723        }
724
725        self.inner.borrow_mut()
726            .push_geometry(&vertices, &indices, false);
727    }
728
729    pub fn draw_circle_filled(
730        &mut self,
731        center: Vector2,
732        radius: f32,
733        segments: u32,
734        color: Color,
735    ) {
736        if segments < 3 {
737            return;
738        }
739
740        let angle_step = std::f32::consts::PI * 2.0 / segments as f32;
741        let vertices = &mut self.vertex_cache;
742        let indices = &mut self.index_cache;
743
744        vec_clear(vertices);
745        vec_clear(indices);
746
747        vertices.push(Vertex::new(
748            Vector3::new(center.x, center.y, 0.0),
749            color,
750            Vector2::ZERO,
751        ));
752
753        for i in 0..segments {
754            let angle = angle_step * i as f32;
755            let x = center.x + radius * angle.cos();
756            let y = center.y + radius * angle.sin();
757
758            vertices.push(Vertex::new(Vector3::new(x, y, 0.0), color, Vector2::ZERO));
759            indices.push(i as u16 + 1);
760        }
761
762        triangle_fan_to_list_indices_ref(&mut *indices);
763
764        if indices.is_empty() {
765            return;
766        }
767
768        self.inner.borrow_mut()
769            .push_geometry(&vertices, &indices, false);
770    }
771
772    pub fn draw_rect_image(&mut self, pos: Vector2, size: Vector2, color: Color) {
773        let mut inner = self.inner.borrow_mut();
774        let uv: RectF = inner.get_absolute_uv();
775
776        let vertices = [
777            Vertex::new(
778                Vector3::new(pos.x, pos.y, 0.0),
779                color,
780                Vector2::new(uv.x, uv.y),
781            ),
782            Vertex::new(
783                Vector3::new(pos.x + size.x, pos.y, 0.0),
784                color,
785                Vector2::new(uv.w, uv.y),
786            ),
787            Vertex::new(
788                Vector3::new(pos.x + size.x, pos.y + size.y, 0.0),
789                color,
790                Vector2::new(uv.w, uv.h),
791            ),
792            Vertex::new(
793                Vector3::new(pos.x, pos.y + size.y, 0.0),
794                color,
795                Vector2::new(uv.x, uv.h),
796            ),
797        ];
798
799        let indices = [0, 1, 2, 0, 2, 3];
800        inner.push_geometry(&vertices, &indices, true);
801    }
802
803    pub fn draw_rect_image_colors(
804        &mut self,
805        pos: Vector2,
806        size: Vector2,
807        color_tl: Color,
808        color_tr: Color,
809        color_br: Color,
810        color_bl: Color,
811    ) {
812        let mut inner = self.inner.borrow_mut();
813        let uv = inner.get_absolute_uv();
814
815        let vertices = [
816            Vertex::new(
817                Vector3::new(pos.x, pos.y, 0.0),
818                color_tl,
819                Vector2::new(uv.x, uv.y),
820            ),
821            Vertex::new(
822                Vector3::new(pos.x + size.x, pos.y, 0.0),
823                color_tr,
824                Vector2::new(uv.w, uv.y),
825            ),
826            Vertex::new(
827                Vector3::new(pos.x + size.x, pos.y + size.y, 0.0),
828                color_br,
829                Vector2::new(uv.w, uv.h),
830            ),
831            Vertex::new(
832                Vector3::new(pos.x, pos.y + size.y, 0.0),
833                color_bl,
834                Vector2::new(uv.x, uv.h),
835            ),
836        ];
837
838        let indices = [0, 1, 2, 0, 2, 3];
839        inner.push_geometry(&vertices, &indices, true);
840    }
841
842    pub fn draw_triangle_image(&mut self, a: Vector2, b: Vector2, c: Vector2, color: Color) {
843        let mut inner = self.inner.borrow_mut();
844        let uv = inner.get_absolute_uv();
845
846        let vertices = [
847            Vertex::new(Vector3::new(a.x, a.y, 0.0), color, Vector2::new(uv.x, uv.y)),
848            Vertex::new(Vector3::new(b.x, b.y, 0.0), color, Vector2::new(uv.w, uv.y)),
849            Vertex::new(
850                Vector3::new(c.x, c.y, 0.0),
851                color,
852                Vector2::new(uv.w * 0.5, uv.h),
853            ),
854        ];
855
856        let indices = [0, 1, 2];
857        inner.push_geometry(&vertices, &indices, true);
858    }
859
860    pub fn draw_circle_image(&mut self, center: Vector2, radius: f32, segments: u32, color: Color) {
861        if segments < 3 {
862            return;
863        }
864
865        let mut inner = self.inner.borrow_mut();
866        let uv = inner.get_absolute_uv();
867
868        let angle_step = std::f32::consts::PI * 2.0 / segments as f32;
869        let mut vertices = Vec::with_capacity(segments as usize);
870        let mut indices = Vec::with_capacity(segments as usize * 3);
871
872        for i in 0..segments {
873            let angle = angle_step * i as f32;
874            let x = center.x + radius * angle.cos();
875            let y = center.y + radius * angle.sin();
876
877            let u = uv.x + (uv.w - uv.x) * (angle.cos() * 0.5 + 0.5);
878            let v = uv.y + (uv.h - uv.y) * (angle.sin() * 0.5 + 0.5);
879
880            vertices.push(Vertex::new(
881                Vector3::new(x, y, 0.0),
882                color,
883                Vector2::new(u, v),
884            ));
885
886            indices.push(i as u16);
887        }
888
889        triangle_fan_to_list_indices_ref(&mut indices);
890
891        if indices.is_empty() {
892            return;
893        }
894
895        inner.push_geometry(&vertices, &indices, true);
896    }
897
898    pub fn set_scissor(&mut self, scissor: RectF) {
899        let mut inner = self.inner.borrow_mut();
900        inner.scissor = Some(scissor);
901    }
902
903    pub fn set_viewport(&mut self, viewport: RectF) {
904        let mut inner = self.inner.borrow_mut();
905        inner.viewport = Some(viewport);
906    }
907
908    pub fn set_texture(&mut self, texture: Option<&Texture>) {
909        self.set_texture_ex(texture, None);
910    }
911
912    pub fn set_texture_ex(
913        &mut self,
914        texture: Option<&Texture>,
915        sampler: Option<TextureSampler>,
916    ) {
917        let mut inner = self.inner.borrow_mut();
918
919        match texture {
920            Some(texture) => {
921                let texture_ref = texture.inner.borrow();
922
923                #[cfg(any(debug_assertions, feature = "enable-release-validation"))]
924                if !texture_ref.usages.contains(TextureUsage::Sampler) {
925                    panic!("Texture must be created with TextureUsage::Sampler");
926                }
927
928                let default_sampler = TextureSampler::DEFAULT;
929                let sampler = sampler.unwrap_or(default_sampler);
930
931                inner.texture = Some((texture.clone(), sampler));
932            }
933            None => {
934                inner.texture = None;
935            }
936        }
937    }
938
939    pub fn set_texture_uv(&mut self, texture_uv: Option<RectF>) {
940        let mut inner = self.inner.borrow_mut();
941
942        match texture_uv {
943            Some(uv) => {
944                inner.texture_uv = Some(uv);
945            }
946            None => {
947                inner.texture_uv = None;
948            }
949        }
950    }
951
952    pub fn set_texture_atlas(&mut self, atlas: Option<(&TextureAtlas, &str)>) {
953        self.set_texture_atlas_ex(atlas);
954    }
955
956    pub fn set_texture_atlas_ex(
957        &mut self,
958        atlas: Option<(&TextureAtlas, &str)>,
959    ) {
960        match atlas {
961            Some((atlas, id)) => {
962                let tex_coord = atlas.get_id(id);
963
964                #[cfg(any(debug_assertions, feature = "enable-release-validation"))]
965                if tex_coord.is_none() {
966                    panic!("Texture atlas does not contain the specified id: {}", id);
967                }
968
969                let (tex_coord, _) = tex_coord.unwrap();
970                let texture = atlas.get_texture();
971
972                let mut inner = self.inner.borrow_mut();
973
974                let default_sampler = TextureSampler::DEFAULT;
975                inner.texture_atlas_uv = Some(tex_coord);
976                inner.texture = Some((
977                    texture.clone(),
978                    default_sampler,
979                ));
980            }
981            None => {
982                self.inner.borrow_mut().texture_atlas_uv = None;
983                return;
984            }
985        };
986    }
987
988    pub fn set_shader(&mut self, shader: Option<&GraphicsShader>) {
989        let mut inner = self.inner.borrow_mut();
990
991        match shader {
992            Some(shader) => {
993                let shader_ref = shader.inner.borrow();
994
995                #[cfg(any(debug_assertions, feature = "enable-release-validation"))]
996                {
997                    let mut fullfiled = false;
998                    for binding in shader_ref.reflection.iter() {
999                        use super::super::shader::types::{ShaderReflect, ShaderBindingType};
1000
1001                        let bindings = match binding {
1002                            ShaderReflect::Fragment { bindings, .. } => bindings,
1003                            ShaderReflect::VertexFragment { bindings, .. } => bindings,
1004                            _ => continue,
1005                        };
1006
1007                        if bindings.iter().any(|b| {
1008                            b.group == 0
1009                                && b.binding == 0
1010                                && matches!(b.ty, ShaderBindingType::Texture(_))
1011                        }) && bindings.iter().any(|b| {
1012                            b.group == 0
1013                                && b.binding == 1
1014                                && matches!(b.ty, ShaderBindingType::Sampler(_))
1015                        }) {
1016                            fullfiled = true;
1017                            break;
1018                        }
1019                    }
1020
1021                    if !fullfiled {
1022                        panic!(
1023                            "Required shader bindings where group 0, binding 0 for texture or group 0, binding 1 are missing for sampler"
1024                        );
1025                    }
1026                }
1027
1028                inner.shader = Some(shader.clone());
1029            }
1030            None => {
1031                inner.shader = None;
1032            }
1033        }
1034    }
1035
1036    pub(crate) fn end(&mut self) {
1037        let mut inner = self.inner.borrow_mut();
1038
1039        #[cfg(any(debug_assertions, feature = "enable-release-validation"))]
1040        if inner.vertices.is_empty() {
1041            crate::dbg_log!(
1042                "DrawingContext::end: No vertices to draw, did you forget to call a drawing function?"
1043            );
1044
1045            return;
1046        }
1047
1048        if let Some(queue) = inner.current_queue.take() {
1049            inner.queue.push(queue);
1050        }
1051
1052        let mut queues = inner.queue.drain(..).collect::<Vec<_>>();
1053        let mut vertices = inner.vertices.drain(..).collect::<Vec<_>>();
1054        let indices = inner.indices.drain(..).collect::<Vec<_>>();
1055
1056        {
1057            let graphics_inner = inner.pass.graphics.borrow();
1058            let drawing = graphics_inner.drawing_state.as_ref().unwrap().borrow();
1059            
1060            let swapchain_size = {
1061                let renderpass_inner = inner.pass.inner.borrow_mut();
1062
1063                Vector2::new(
1064                    renderpass_inner.surface_size.x as f32,
1065                    renderpass_inner.surface_size.y as f32,
1066                )
1067            };
1068
1069            for vertex in vertices.iter_mut() {
1070                vertex.position.x = vertex.position.x / swapchain_size.x * 2.0 - 1.0;
1071                vertex.position.y = 1.0 - (vertex.position.y / swapchain_size.y * 2.0);
1072            }
1073
1074            for queue in queues.iter_mut() {
1075                if queue.texture.is_none() {
1076                    let default_texture = drawing
1077                        .texture
1078                        .clone();
1079
1080                    let sampler = TextureSampler::DEFAULT;
1081                    queue.texture = Some((default_texture, sampler));
1082                }
1083
1084                if queue.shader.is_none() {
1085                    let default_shader = drawing
1086                        .shader
1087                        .clone();
1088
1089                    queue.shader = Some(default_shader);
1090                }
1091            }
1092        };
1093
1094        let (vertex_buffer, index_buffer) = {
1095            let mut graphics_inner = inner.pass.graphics.borrow_mut();
1096            
1097            let vertex_buffer = graphics_inner
1098                .create_staging_buffer(bytemuck::cast_slice(&vertices), wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST);
1099
1100            let index_buffer = graphics_inner
1101                .create_staging_buffer(bytemuck::cast_slice(&indices), wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST);
1102
1103            (vertex_buffer, index_buffer)
1104        };
1105
1106        for queue in queues {
1107            let pass = &mut inner.pass;
1108
1109            pass.set_scissor(queue.scissors);
1110            pass.set_viewport(queue.viewport, 0.0, 1.0);
1111
1112            let (texture, sampler) = queue.texture.as_ref().unwrap();
1113
1114            pass.set_shader(queue.shader.as_ref());
1115            pass
1116                .set_gpu_buffer_wgpu(Some(vertex_buffer.clone()), Some(index_buffer.clone()));
1117
1118            pass.set_attachment_texture(0, 0, Some(&texture));
1119            pass.set_attachment_sampler(0, 1, Some(sampler));
1120
1121            pass
1122                .draw_indexed(queue.start_index..queue.count, queue.start_vertex as i32, 1);
1123        }
1124    }
1125}
1126
1127impl Drop for DrawingContext {
1128    fn drop(&mut self) {
1129        if std::thread::panicking() {
1130            return;
1131        }
1132
1133        self.end();
1134    }
1135}
1136
1137// Memory optimization purpose.
1138thread_local! {
1139    static INDICES_VEC: RefCell<Vec<u16>> = RefCell::new(Vec::new());
1140}
1141
1142/// Helper to convert triangle fan to tringle list indices,
1143/// since the wgpu does not support triangle fans directly.
1144fn triangle_fan_to_list_indices_ref(param: &mut Vec<u16>) {
1145    if param.len() < 3 {
1146        return;
1147    }
1148
1149    INDICES_VEC.with(|vec| {
1150        let mut vec = vec.borrow_mut();
1151
1152        vec_clear(&mut vec);
1153        vec.resize((param.len() - 2) * 3, 0);
1154
1155        for i in 1..(param.len() - 1) {
1156            vec[(i - 1) * 3] = param[0];
1157            vec[(i - 1) * 3 + 1] = param[i];
1158            vec[(i - 1) * 3 + 2] = param[i + 1];
1159        }
1160
1161        vec_clear(param);
1162        param.extend_from_slice(&vec);
1163    });
1164}
1165
1166/// Quick and dirty way to clear a vector without dropping its elements.
1167fn vec_clear<T>(vec: &mut Vec<T>) {
1168    // SAFETY: Only used for clearing the vector of plain struct
1169    // no references or pointers to heap-allocated data
1170    unsafe {
1171        assert!(
1172            std::mem::needs_drop::<T>() == false,
1173            "Cannot clear vector of type that needs drop"
1174        );
1175
1176        vec.set_len(0);
1177    }
1178}