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