Skip to main content

care_game/graphics/
render_2d.rs

1use std::{fmt::Debug, sync::OnceLock};
2
3use bytemuck::{Pod, Zeroable};
4use half::f16;
5use rusttype::{gpu_cache::Cache as FontCache, PositionedGlyph};
6use wgpu::VertexAttribute;
7use winit::window::WindowId;
8
9use crate::{
10    math::{Fl, Mat3, Vec2, Vec4},
11    prelude::Mat2,
12};
13
14use super::{Font, Texture};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17/// How to join lines together
18pub enum LineJoinStyle {
19    /// None/disconnected
20    None,
21    /// Merge the two lines points on the left and right
22    Merge,
23    /// Angled so it looks like both sides of the line meet where they logically would
24    ///
25    /// Limited at extreme angles to avoid weird visual glitches
26    Miter,
27    /// Like miter, angled so it looks like both sides of the line meet where they logically would
28    ///
29    /// Not limited at extreme angles
30    MiterUnlimited,
31    /// Just bevel to fill in the gap with a flat line
32    Bevel,
33    /// Rounded with a curve
34    Rounded,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38/// How to end lines
39pub enum LineEndStyle {
40    /// flattened
41    Flat,
42    /// Angled little point
43    Point,
44    /// Rounded circular point
45    Rounded,
46}
47
48#[derive(Debug)]
49pub(crate) enum DrawCommandData {
50    Rect {
51        pos: Vec2,
52        size: Vec2,
53        rotation: Fl,
54        corner_radii: [Fl; 4],
55    },
56    Texture {
57        texture: Texture,
58        pos: Vec2,
59        scale: Vec2,
60        source: (Vec2, Vec2),
61        rotation: Fl,
62        corner_radii: [Fl; 4],
63    },
64    TextChar {
65        glyph: PositionedGlyph<'static>,
66        font: u32,
67    },
68    Triangle {
69        verts: [Vec2; 3],
70        tex_uvs: Option<(Texture, [Vec2; 3])>,
71    },
72    Circle {
73        center: Vec2,
74        radius: Fl,
75        elipseness: Vec2,
76    },
77    Line {
78        points: Vec<(Vec2, Fl, LineJoinStyle)>,
79        ends: (LineEndStyle, LineEndStyle),
80    },
81}
82
83#[derive(Debug)]
84pub(crate) struct DrawCommand {
85    pub transform: Mat3,
86    pub colour: Vec4,
87    pub data: DrawCommandData,
88}
89
90#[repr(C)]
91#[derive(Debug, Default, Clone, Copy, Pod, Zeroable)]
92pub(crate) struct Vertex2d {
93    position: [f32; 2],
94    uv: [f16; 2],
95    colour: [u8; 4],
96    rounding_box: [f16; 4],
97    rounding_values: [u8; 4],
98    tex: u32,
99}
100
101impl Vertex2d {
102    pub fn descriptor() -> wgpu::VertexBufferLayout<'static> {
103        const ATTRS: [VertexAttribute; 6] = wgpu::vertex_attr_array![
104            0 => Float32x2, // position
105            1 => Float16x2, // UV
106            2 => Unorm8x4, // Colour
107            3 => Float16x4, // UV Rect for rounding
108            4 => Unorm8x4, // Corner radii
109            5 => Uint32, // Texture index
110        ];
111        wgpu::VertexBufferLayout {
112            array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,
113            step_mode: wgpu::VertexStepMode::Vertex,
114            attributes: &ATTRS,
115        }
116    }
117}
118
119pub(crate) struct CareRenderState {
120    pub transform_stack: Vec<Mat3>,
121    pub current_transform: Mat3,
122    pub current_colour: Vec4,
123    pub current_surface: WindowId,
124    pub commands: Vec<DrawCommand>,
125    pub max_textures: usize,
126    pub font_cache: FontCache<'static>,
127    pub font_cache_texture: OnceLock<Texture>,
128    pub default_font: Font,
129    pub next_font_id: u32,
130    pub line_end_style: LineEndStyle,
131    pub line_join_style: LineJoinStyle,
132}
133
134impl Debug for CareRenderState {
135    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136        f.debug_struct("CareRenderState")
137            .field("transform_stack", &self.transform_stack)
138            .field("current_transform", &self.current_transform)
139            .field("current_colour", &self.current_colour)
140            .field("current_surface", &self.current_surface)
141            .field("commands", &self.commands)
142            .field("max_textures", &self.max_textures)
143            .field("default_font", &self.default_font)
144            .field("line_end_style", &self.line_end_style)
145            .field("line_join_style", &self.line_join_style)
146            .finish_non_exhaustive()
147    }
148}
149
150#[derive(Debug, Default)]
151pub(crate) struct DrawCall<T: bytemuck::Pod + Default> {
152    pub(crate) vertices: Vec<T>,
153    pub(crate) indices: Vec<u32>,
154    pub(crate) textures: Vec<Texture>,
155}
156
157fn uv_pos(pos: Vec2) -> [f16; 2] {
158    [f16::from_f32(pos.x()), f16::from_f32(pos.y())]
159}
160
161fn uv_bb(pos: Vec2, size: Vec2) -> [f16; 4] {
162    [
163        f16::from_f32(pos.x()),
164        f16::from_f32(pos.y()),
165        f16::from_f32(size.x()),
166        f16::from_f32(size.y()),
167    ]
168}
169
170fn helper_line_segment_normal(pos1: Vec2, pos2: Vec2, width: f32) -> Vec2 {
171    (pos2 - pos1).normalize_or(Vec2::new(0.0, 0.0)).tangent() * width / 2.0
172}
173
174fn helper_add_verts_for_line_segment(
175    verts: &mut Vec<Vertex2d>,
176    vert_pos: &dyn Fn((Fl, Fl), Fl) -> [f32; 2],
177    colour: [u8; 4],
178    pos1: Vec2,
179    pos2: Vec2,
180    width: f32,
181) {
182    let norm = helper_line_segment_normal(pos1, pos2, width);
183    verts.push(Vertex2d {
184        position: vert_pos((pos1.x() + norm.x(), pos1.y() + norm.y()), 0.0),
185        uv: uv_pos(Vec2::new(0, 0)),
186        colour,
187        rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
188        rounding_values: [0, 0, 0, 0],
189        tex: 0,
190    });
191    verts.push(Vertex2d {
192        position: vert_pos((pos1.x() - norm.x(), pos1.y() - norm.y()), 0.0),
193        uv: uv_pos(Vec2::new(0, 0)),
194        colour,
195        rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
196        rounding_values: [0, 0, 0, 0],
197        tex: 0,
198    });
199}
200
201fn helper_add_verts_for_merge_segment(
202    verts: &mut Vec<Vertex2d>,
203    vert_pos: &dyn Fn((Fl, Fl), Fl) -> [f32; 2],
204    colour: [u8; 4],
205    pos1: Vec2,
206    pos2: Vec2,
207    pos3: Vec2,
208    width: f32,
209) {
210    let norm1 = helper_line_segment_normal(pos1, pos2, width);
211    let norm2 = helper_line_segment_normal(pos2, pos3, width);
212    let norm = (norm1 + norm2) / 2.0;
213    verts.push(Vertex2d {
214        position: vert_pos((pos2.x() + norm.x(), pos2.y() + norm.y()), 0.0),
215        uv: uv_pos(Vec2::new(0, 0)),
216        colour,
217
218        rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
219        rounding_values: [0, 0, 0, 0],
220        tex: 0,
221    });
222    verts.push(Vertex2d {
223        position: vert_pos((pos2.x() - norm.x(), pos2.y() - norm.y()), 0.0),
224        uv: uv_pos(Vec2::new(0, 0)),
225        colour,
226
227        rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
228        rounding_values: [0, 0, 0, 0],
229        tex: 0,
230    });
231}
232
233fn line_line_intersect(l1: (Vec2, Vec2), l2: (Vec2, Vec2)) -> Option<Vec2> {
234    let d = (l1.0.x() - l1.1.x()) * (l2.0.y() - l2.1.y())
235        - (l2.0.x() - l2.1.x()) * (l1.0.y() - l1.1.y());
236    if d.abs() <= 0.001 {
237        return None;
238    }
239    Some(
240        Vec2::new(
241            (l1.0.x() * l1.1.y() - l1.0.y() * l1.1.x()) * (l2.0.x() - l2.1.x())
242                - (l1.0.x() - l1.1.x()) * (l2.0.x() * l2.1.y() - l2.0.y() * l2.1.x()),
243            (l1.0.x() * l1.1.y() - l1.0.y() * l1.1.x()) * (l2.0.y() - l2.1.y())
244                - (l1.0.y() - l1.1.y()) * (l2.0.x() * l2.1.y() - l2.0.y() * l2.1.x()),
245        ) / d,
246    )
247}
248
249fn limit_dist(source: Vec2, dest: Vec2, max_dist: Fl) -> Vec2 {
250    if (dest - source).length() <= max_dist {
251        dest
252    } else {
253        source + (dest - source).normalize_or(Vec2::new(0, 0)) * max_dist
254    }
255}
256
257fn helper_do_line_join(
258    vertices: &mut Vec<Vertex2d>,
259    vert_pos: &dyn Fn((Fl, Fl), Fl) -> [f32; 2],
260    points: (Vec2, Vec2, Vec2),
261    width: Fl,
262    style: LineJoinStyle,
263    colour: [u8; 4],
264    line_idx: ((u32, u32), (u32, u32)),
265) -> Vec<u32> {
266    let norm1 = helper_line_segment_normal(points.1, points.0, width);
267    let line1_points = (
268        Vec2::new(points.1.x() - norm1.x(), points.1.y() - norm1.y()),
269        Vec2::new(points.1.x() + norm1.x(), points.1.y() + norm1.y()),
270    );
271    let norm2 = helper_line_segment_normal(points.1, points.2, width);
272    let line2_points = (
273        Vec2::new(points.1.x() + norm2.x(), points.1.y() + norm2.y()),
274        Vec2::new(points.1.x() - norm2.x(), points.1.y() - norm2.y()),
275    );
276    match style {
277        LineJoinStyle::None => vec![],
278        LineJoinStyle::Merge => vec![], // TODO
279        LineJoinStyle::Miter | LineJoinStyle::MiterUnlimited => {
280            let point_a = line_line_intersect(
281                (line1_points.0, line1_points.0 - norm1.tangent()),
282                (line2_points.0, line2_points.0 - norm2.tangent()),
283            )
284            .unwrap_or(points.1);
285            let point_b = line_line_intersect(
286                (line1_points.1, line1_points.1 - norm1.tangent()),
287                (line2_points.1, line2_points.1 - norm2.tangent()),
288            )
289            .unwrap_or(points.1);
290            let (point_a, point_b) = if style == LineJoinStyle::Miter {
291                (
292                    limit_dist(points.1, point_a, width * 2.0),
293                    limit_dist(points.1, point_b, width * 2.0),
294                )
295            } else {
296                (point_a, point_b)
297            };
298            let n = vertices.len() as u32;
299            vertices.push(Vertex2d {
300                position: vert_pos((points.1.x(), points.1.y()), 0.0),
301                uv: uv_pos(Vec2::new(0, 0)),
302                colour,
303                rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
304                rounding_values: [0, 0, 0, 0],
305                tex: 0,
306            });
307            vertices.push(Vertex2d {
308                position: vert_pos((point_a.x(), point_a.y()), 0.0),
309                uv: uv_pos(Vec2::new(0, 0)),
310                colour,
311                rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
312                rounding_values: [0, 0, 0, 0],
313                tex: 0,
314            });
315            vertices.push(Vertex2d {
316                position: vert_pos((point_b.x(), point_b.y()), 0.0),
317                uv: uv_pos(Vec2::new(0, 0)),
318                colour,
319                rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
320                rounding_values: [0, 0, 0, 0],
321                tex: 0,
322            });
323            vec![
324                n,
325                line_idx.0 .0,
326                line_idx.1 .0,
327                n + 1,
328                line_idx.1 .0,
329                line_idx.0 .0,
330                n,
331                line_idx.0 .1,
332                line_idx.1 .1,
333                n + 2,
334                line_idx.1 .1,
335                line_idx.0 .1,
336            ]
337        }
338        LineJoinStyle::Bevel => {
339            let n = vertices.len() as u32;
340            vertices.push(Vertex2d {
341                position: vert_pos((points.1.x(), points.1.y()), 0.0),
342                uv: uv_pos(Vec2::new(0, 0)),
343                colour,
344                rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
345                rounding_values: [0, 0, 0, 0],
346                tex: 0,
347            });
348            vec![
349                n,
350                line_idx.0 .0,
351                line_idx.1 .0,
352                n,
353                line_idx.1 .1,
354                line_idx.0 .1,
355            ]
356        }
357        LineJoinStyle::Rounded => vec![], // TODO
358    }
359}
360
361impl CareRenderState {
362    pub fn reset(&mut self) {
363        self.transform_stack.clear();
364        self.current_transform = Mat3::ident();
365        self.current_colour = Vec4::new(1, 1, 1, 1);
366        self.commands.clear();
367    }
368    pub fn render(&mut self, screen_size: Vec2) -> Vec<DrawCall<Vertex2d>> {
369        let mut draw_calls = Vec::new();
370        let mut cdc = DrawCall::default();
371        let mut use_tex = |texture: &Texture, cdc: &mut DrawCall<Vertex2d>| {
372            (if let Some(idx) = cdc.textures.iter().position(|t| t == texture) {
373                // offset by one because 0 represents no texture.
374                idx + 1
375            } else if cdc.textures.len() < self.max_textures {
376                cdc.textures.push(texture.clone());
377                // Using len accounts for said offset
378                cdc.textures.len()
379            } else {
380                let mut new_draw_call = DrawCall::default();
381                std::mem::swap(&mut new_draw_call, cdc);
382                draw_calls.push(new_draw_call);
383                cdc.textures.push(texture.clone());
384                cdc.textures.len()
385            }) as u32
386        };
387        for command in self.commands.drain(..) {
388            let vert_pos = |v: (Fl, Fl), rot: Fl| {
389                let v = (&command.transform) * Vec2::from(v).rotated(rot);
390                [v.x() / screen_size.x(), v.y() / screen_size.y()]
391            };
392            let colour = [
393                (command.colour.0.x * 255.99) as u8,
394                (command.colour.0.y * 255.99) as u8,
395                (command.colour.0.z * 255.99) as u8,
396                (command.colour.0.w * 255.99) as u8,
397            ];
398            match command.data {
399                DrawCommandData::Rect {
400                    pos,
401                    size,
402                    rotation,
403                    corner_radii,
404                } => {
405                    let n = cdc.vertices.len() as u32;
406                    let (uv, _uv_per_pix) = if size.x() > size.y() {
407                        (Vec2::new(1, size.y() / size.x()), 2.0 / size.x())
408                    } else {
409                        (Vec2::new(1, size.x() / size.y()), 2.0 / size.y())
410                    };
411                    let corner_radii = corner_radii.map(|n| (n * 255.9).clamp(0.0, 255.0) as u8);
412                    cdc.vertices.push(Vertex2d {
413                        position: vert_pos((pos.x(), pos.y()), rotation),
414                        uv: uv_pos(Vec2::new(0, 0)),
415                        colour,
416                        rounding_box: uv_bb(Vec2::new(0, 0), uv),
417                        rounding_values: corner_radii,
418                        tex: 0,
419                    });
420                    cdc.vertices.push(Vertex2d {
421                        position: vert_pos((pos.x() + size.x(), pos.y()), rotation),
422                        uv: uv_pos(Vec2::new(uv.x(), 0)),
423                        colour,
424                        rounding_box: uv_bb(Vec2::new(0, 0), uv),
425                        rounding_values: corner_radii,
426                        tex: 0,
427                    });
428                    cdc.vertices.push(Vertex2d {
429                        position: vert_pos((pos.x(), pos.y() + size.y()), rotation),
430                        uv: uv_pos(Vec2::new(0, uv.y())),
431                        colour,
432                        rounding_box: uv_bb(Vec2::new(0, 0), uv),
433                        rounding_values: corner_radii,
434                        tex: 0,
435                    });
436                    cdc.vertices.push(Vertex2d {
437                        position: vert_pos((pos.x() + size.x(), pos.y() + size.y()), rotation),
438                        uv: uv_pos(uv),
439                        colour,
440                        rounding_box: uv_bb(Vec2::new(0, 0), uv),
441                        rounding_values: corner_radii,
442                        tex: 0,
443                    });
444                    cdc.indices
445                        .extend_from_slice(&[n, n + 1, n + 2, n + 2, n + 1, n + 3])
446                }
447                DrawCommandData::Texture {
448                    texture,
449                    pos,
450                    scale,
451                    source,
452                    rotation,
453                    corner_radii,
454                } => {
455                    let tex_size = texture.size();
456                    let tex = use_tex(&texture, &mut cdc);
457                    let n = cdc.vertices.len() as u32;
458                    let size = tex_size * scale;
459                    let uv_base = source.0 / tex_size;
460                    let uv_size = source.1 / tex_size;
461                    let corner_radii = corner_radii.map(|n| (n * 255.9).clamp(0.0, 255.0) as u8);
462                    cdc.vertices.push(Vertex2d {
463                        position: vert_pos((pos.0.x, pos.0.y), rotation),
464                        uv: uv_pos(Vec2::new(uv_base.x(), uv_base.y())),
465                        colour,
466                        rounding_box: uv_bb(uv_base, uv_size),
467                        rounding_values: corner_radii,
468                        tex,
469                    });
470                    cdc.vertices.push(Vertex2d {
471                        position: vert_pos((pos.0.x + size.0.x, pos.0.y), rotation),
472                        uv: uv_pos(Vec2::new(uv_base.x() + uv_size.x(), uv_base.y())),
473                        colour,
474                        rounding_box: uv_bb(uv_base, uv_size),
475                        rounding_values: corner_radii,
476                        tex,
477                    });
478                    cdc.vertices.push(Vertex2d {
479                        position: vert_pos((pos.0.x, pos.0.y + size.0.y), rotation),
480                        uv: uv_pos(Vec2::new(uv_base.x(), uv_base.y() + uv_size.y())),
481                        colour,
482                        rounding_box: uv_bb(uv_base, uv_size),
483                        rounding_values: corner_radii,
484                        tex,
485                    });
486                    cdc.vertices.push(Vertex2d {
487                        position: vert_pos((pos.0.x + size.0.x, pos.0.y + size.0.y), rotation),
488                        uv: uv_pos(Vec2::new(
489                            uv_base.x() + uv_size.x(),
490                            uv_base.y() + uv_size.y(),
491                        )),
492                        colour,
493                        rounding_box: uv_bb(uv_base, uv_size),
494                        rounding_values: corner_radii,
495                        tex,
496                    });
497                    cdc.indices
498                        .extend_from_slice(&[n, n + 1, n + 2, n + 2, n + 1, n + 3])
499                }
500                DrawCommandData::TextChar { glyph, font } => {
501                    let texture = self.font_cache_texture.get().unwrap();
502                    let tex = use_tex(texture, &mut cdc);
503                    let n = cdc.vertices.len() as u32;
504                    if let Some(rect) = self.font_cache.rect_for(font as usize, &glyph).unwrap() {
505                        let pos = Vec2::new(rect.1.min.x, rect.1.min.y);
506                        let size = Vec2::new(rect.1.max.x, rect.1.max.y) - pos;
507                        let uv_base = Vec2::new(rect.0.min.x, rect.0.min.y);
508                        let uv_size = Vec2::new(rect.0.max.x, rect.0.max.y) - uv_base;
509                        cdc.vertices.push(Vertex2d {
510                            position: vert_pos((pos.0.x, pos.0.y), 0.0),
511                            uv: uv_pos(Vec2::new(uv_base.x(), uv_base.y())),
512                            colour,
513                            rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
514                            rounding_values: [0, 0, 0, 0],
515                            tex,
516                        });
517                        cdc.vertices.push(Vertex2d {
518                            position: vert_pos((pos.0.x + size.0.x, pos.0.y), 0.0),
519                            uv: uv_pos(Vec2::new(uv_base.x() + uv_size.x(), uv_base.y())),
520                            colour,
521                            rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
522                            rounding_values: [0, 0, 0, 0],
523                            tex,
524                        });
525                        cdc.vertices.push(Vertex2d {
526                            position: vert_pos((pos.0.x, pos.0.y + size.0.y), 0.0),
527                            uv: uv_pos(Vec2::new(uv_base.x(), uv_base.y() + uv_size.y())),
528                            colour,
529                            rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
530                            rounding_values: [0, 0, 0, 0],
531                            tex,
532                        });
533                        cdc.vertices.push(Vertex2d {
534                            position: vert_pos((pos.0.x + size.0.x, pos.0.y + size.0.y), 0.0),
535                            uv: uv_pos(Vec2::new(
536                                uv_base.x() + uv_size.x(),
537                                uv_base.y() + uv_size.y(),
538                            )),
539                            colour,
540                            rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
541                            rounding_values: [0, 0, 0, 0],
542                            tex,
543                        });
544                        cdc.indices
545                            .extend_from_slice(&[n, n + 1, n + 2, n + 2, n + 1, n + 3])
546                    }
547                }
548                DrawCommandData::Triangle { verts, tex_uvs } => {
549                    let (tex, uvs) = if let Some((tex, uvs)) = tex_uvs {
550                        (use_tex(&tex, &mut cdc), uvs)
551                    } else {
552                        (0, [Vec2::new(0.5, 0.5); 3])
553                    };
554                    let n = cdc.vertices.len() as u32;
555                    for (pos, uv) in verts.iter().zip(uvs.iter()) {
556                        cdc.vertices.push(Vertex2d {
557                            position: vert_pos((pos.x(), pos.y()), 0.0),
558                            uv: uv_pos(*uv),
559                            colour,
560                            rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
561                            rounding_values: [0, 0, 0, 0],
562                            tex,
563                        });
564                    }
565                    cdc.indices.extend_from_slice(&[n, n + 1, n + 2])
566                }
567                DrawCommandData::Circle {
568                    center,
569                    radius,
570                    elipseness,
571                } => {
572                    let n = cdc.vertices.len() as u32;
573                    let sqrt_3 = (3.0f32).sqrt();
574                    let left = Vec2::new(-sqrt_3 * radius, -radius);
575                    let right = Vec2::new(sqrt_3 * radius, -radius);
576                    let top = Vec2::new(0.0, 2.0 * radius);
577                    let e_dir = elipseness.normalize_or(Vec2::new(1, 0));
578                    let e_tan = e_dir.tangent();
579                    let e_len = elipseness.length() + 1.0;
580                    let e_mat =
581                        Mat2::new(e_dir.x() * e_len, -e_tan.x(), e_dir.y() * e_len, -e_tan.y());
582                    let left = center + &e_mat * left;
583                    let right = center + &e_mat * right;
584                    let top = center + &e_mat * top;
585                    let left_uv = Vec2::new((1.0 - sqrt_3) / 2.0, 0.0);
586                    let right_uv = Vec2::new(1.0 + (sqrt_3 - 1.0) / 2.0, 0.0);
587                    let top_uv = Vec2::new(0.5, 1.5);
588                    cdc.vertices.push(Vertex2d {
589                        position: vert_pos((left.x(), left.y()), 0.0),
590                        uv: uv_pos(left_uv),
591                        colour,
592                        rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
593                        rounding_values: [255, 255, 255, 255],
594                        tex: 0,
595                    });
596                    cdc.vertices.push(Vertex2d {
597                        position: vert_pos((top.x(), top.y()), 0.0),
598                        uv: uv_pos(top_uv),
599                        colour,
600                        rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
601                        rounding_values: [255, 255, 255, 255],
602                        tex: 0,
603                    });
604                    cdc.vertices.push(Vertex2d {
605                        position: vert_pos((right.x(), right.y()), 0.0),
606                        uv: uv_pos(right_uv),
607                        colour,
608                        rounding_box: uv_bb(Vec2::new(0, 0), Vec2::new(1, 1)),
609                        rounding_values: [255, 255, 255, 255],
610                        tex: 0,
611                    });
612                    cdc.indices.extend_from_slice(&[n, n + 1, n + 2])
613                }
614                DrawCommandData::Line { points, ends } => {
615                    // TODO: Line Ends
616                    let mut n = (cdc.vertices.len() as u32, cdc.vertices.len() as u32 + 1);
617                    helper_add_verts_for_line_segment(
618                        &mut cdc.vertices,
619                        &vert_pos,
620                        colour,
621                        points[0].0,
622                        points[1].0,
623                        points[0].1,
624                    );
625                    for segs in points.windows(3) {
626                        let m = cdc.vertices.len() as u32;
627                        if segs[0].2 == LineJoinStyle::Merge {
628                            helper_add_verts_for_merge_segment(
629                                &mut cdc.vertices,
630                                &vert_pos,
631                                colour,
632                                segs[0].0,
633                                segs[1].0,
634                                segs[2].0,
635                                segs[1].1,
636                            );
637                            cdc.indices.extend_from_slice(&[n.0, n.1, m, m, n.1, m + 1]);
638                            n = (m, m + 1);
639                        } else {
640                            helper_add_verts_for_line_segment(
641                                &mut cdc.vertices,
642                                &vert_pos,
643                                colour,
644                                segs[1].0,
645                                segs[0].0,
646                                -segs[1].1,
647                            );
648                            cdc.indices.extend_from_slice(&[n.0, n.1, m, m, n.1, m + 1]);
649                            n = (cdc.vertices.len() as u32, cdc.vertices.len() as u32 + 1);
650                            helper_add_verts_for_line_segment(
651                                &mut cdc.vertices,
652                                &vert_pos,
653                                colour,
654                                segs[1].0,
655                                segs[2].0,
656                                segs[1].1,
657                            );
658                            cdc.indices.append(&mut helper_do_line_join(
659                                &mut cdc.vertices,
660                                &vert_pos,
661                                (segs[0].0, segs[1].0, segs[2].0),
662                                segs[1].1,
663                                segs[1].2,
664                                colour,
665                                ((m, m + 1), n),
666                            ))
667                        }
668                    }
669                    let m = cdc.vertices.len() as u32;
670                    helper_add_verts_for_line_segment(
671                        &mut cdc.vertices,
672                        &vert_pos,
673                        colour,
674                        points[points.len() - 1].0,
675                        points[points.len() - 2].0,
676                        -points[points.len() - 1].1,
677                    );
678                    cdc.indices.extend_from_slice(&[n.0, n.1, m, m, n.1, m + 1]);
679                }
680            }
681        }
682        //println!("{cdc:?}");
683        draw_calls.push(cdc);
684        draw_calls
685    }
686}