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)]
17pub enum LineJoinStyle {
19 None,
21 Merge,
23 Miter,
27 MiterUnlimited,
31 Bevel,
33 Rounded,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum LineEndStyle {
40 Flat,
42 Point,
44 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, 1 => Float16x2, 2 => Unorm8x4, 3 => Float16x4, 4 => Unorm8x4, 5 => Uint32, ];
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![], 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![], }
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 idx + 1
375 } else if cdc.textures.len() < self.max_textures {
376 cdc.textures.push(texture.clone());
377 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 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 draw_calls.push(cdc);
684 draw_calls
685 }
686}