1use std::f32::consts::PI;
5
6use super::Light;
7use crate::color::Rgb;
8use crate::color::Rgbf;
9use crate::font::Font;
10use crate::image::Canvas;
11use crate::image::Cubemap;
12use crate::image::Filter;
13use crate::image::Texture;
14use crate::image::Wrap;
15use crate::math::Mat4;
16use crate::math::Quat;
17use crate::math::Vec2;
18use crate::math::Vec3;
19use crate::mesh::Mesh;
20use crate::mesh::Model;
21use crate::mesh::ModelNode;
22use crate::pipeline::Material;
23use crate::pipeline::Shader;
24use crate::resources::Builtins;
25use crate::resources::Handle;
26
27pub struct Target {
34 fill: Rgb,
36 stroke: Rgb,
37 tint: Rgb,
38 pub(crate) background: Rgb,
39
40 shadows: bool,
42 pub(crate) shadow_depth: f32,
43 pub(crate) shadow_split: f32,
44 pub(crate) shadow_softness: Pcf,
45
46 light_index: usize,
48 pub(crate) lights: [Light; 4],
49 pub(crate) ambient: Vec3,
50 pub(crate) exposure: f32,
51
52 matrix: Mat4,
54 stroke_weight: f32,
55 font_size: u32,
56 shape_mode: ShapeMode,
57 border_mode: BorderMode,
58 filter: Filter,
59 wrap: Wrap,
60
61 shader: Option<Handle<Shader>>,
63 material: Option<Handle<Material>>,
64 font: Option<Handle<Font>>,
65 pub(crate) skybox: Option<Handle<Cubemap>>,
66 pub(crate) builtins: Builtins,
67
68 pub(crate) mesh_orders: Vec<ShaderOrder>,
70 pub(crate) line_orders: Vec<LineOrder>,
71 pub(crate) tri_orders: Vec<TriOrder>,
72 pub(crate) char_orders: Vec<CharOrder>,
73
74 cache: Vec<Cache>,
75}
76
77#[derive(Debug, Copy, Clone, PartialEq, Eq)]
79pub enum ShapeMode {
80 BottomLeft,
82 BottomRight,
84 TopLeft,
86 TopRight,
88 Center,
90}
91
92#[derive(Debug, Copy, Clone, PartialEq, Eq)]
94pub enum BorderMode {
95 Outside,
97 Inside,
99 Center,
102}
103
104#[derive(Debug, Copy, Clone, PartialEq, Eq)]
106pub enum Pcf {
107 X16,
109 X4,
111 Disabled,
113}
114
115pub(crate) struct ShaderOrder {
116 pub(crate) shader: Handle<Shader>,
117 pub(crate) orders: Vec<MaterialOrder>,
118}
119
120pub(crate) struct MaterialOrder {
121 pub(crate) material: Handle<Material>,
122 pub(crate) orders: Vec<MeshOrder>,
123}
124
125pub(crate) struct MeshOrder {
126 pub(crate) mesh: Handle<Mesh>,
127 pub(crate) matrix: Mat4,
128 pub(crate) color: Rgb,
129 pub(crate) shadows: bool,
130 pub(crate) sampler_index: u32,
131}
132
133pub(crate) struct CharOrder {
134 pub(crate) points: [Vec3; 4],
135 pub(crate) uvs: [Vec2; 4],
136 pub(crate) color: Rgb,
137 pub(crate) texture: u32,
138}
139
140pub(crate) struct LineOrder {
141 pub(crate) points: [Vec3; 2],
142 pub(crate) color: Rgb,
143}
144
145pub(crate) struct TriOrder {
146 pub(crate) points: [Vec3; 3],
147 pub(crate) uvs: [Vec2; 3],
148 pub(crate) color: Rgb,
149 pub(crate) texture: u32,
150 pub(crate) sampler_index: u32,
151 pub(crate) opaque: bool,
152}
153
154struct Cache {
155 shader: Option<Handle<Shader>>,
156 material: Option<Handle<Material>>,
157 font: Option<Handle<Font>>,
158
159 background: Rgb,
161 fill: Rgb,
162 stroke: Rgb,
163 tint: Rgb,
164
165 shadows: bool,
167
168 matrix: Mat4,
170 stroke_weight: f32,
171 font_size: u32,
172 shape_mode: ShapeMode,
173 border_mode: BorderMode,
174 filter: Filter,
175 wrap: Wrap,
176}
177
178impl Target {
179 pub(crate) fn new(builtins: &Builtins) -> Self {
180 Self {
181 background: Rgb::gray(255),
182 fill: Rgb::gray(255),
183 stroke: Rgb::gray(0),
184 tint: Rgb::gray(255),
185
186 shadows: false,
187 shadow_depth: 50.0,
188 shadow_split: 0.5,
189 shadow_softness: Pcf::X16,
190
191 lights: [Light::none(); 4],
192 light_index: 0,
193 ambient: Vec3::uniform(0.03),
194 exposure: 1.0,
195
196 matrix: Mat4::identity(),
197 stroke_weight: 2.0,
198 font_size: 24,
199 shape_mode: ShapeMode::Center,
200 border_mode: BorderMode::Center,
201 filter: Filter::Linear,
202 wrap: Wrap::Repeat,
203
204 font: None,
205 shader: None,
206 material: None,
207 skybox: None,
208 builtins: builtins.clone(),
209
210 mesh_orders: vec![],
211 char_orders: vec![],
212 line_orders: vec![],
213 tri_orders: vec![],
214
215 cache: vec![],
216 }
217 }
218
219 pub fn background(&mut self, color: impl Into<Rgb>) {
221 self.background = color.into();
222 }
223
224 pub fn fill(&mut self, color: impl Into<Rgb>) {
226 self.fill = color.into();
227 }
228
229 pub fn stroke(&mut self, color: impl Into<Rgb>) {
231 self.stroke = color.into();
232 }
233
234 pub fn tint(&mut self, color: impl Into<Rgb>) {
236 self.tint = color.into();
237 }
238
239 pub fn material(&mut self, m: &Handle<Material>) {
241 self.material = Some(m.clone());
242 }
243
244 pub fn no_material(&mut self) {
246 self.material = None;
247 }
248
249 pub fn shader(&mut self, s: &Handle<Shader>) {
251 self.shader = Some(s.clone());
252 }
253
254 pub fn no_shader(&mut self) {
256 self.shader = None;
257 }
258
259 pub fn skybox(&mut self, s: &Handle<Cubemap>) {
261 self.skybox = Some(s.clone());
262 }
263
264 pub fn font(&mut self, f: &Handle<Font>) {
266 self.font = Some(f.clone());
267 }
268
269 pub fn no_font(&mut self) {
271 self.font = None;
272 }
273
274 pub fn shadows(&mut self) {
279 self.shadows = true;
280 }
281
282 pub fn no_shadows(&mut self) {
284 self.shadows = false;
285 }
286
287 pub fn shadow_depth(&mut self, d: f32) {
289 self.shadow_depth = d;
290 }
291
292 pub fn shadow_split(&mut self, s: f32) {
297 self.shadow_split = s;
298 }
299
300 pub fn shadow_softness(&mut self, pcf: Pcf) {
302 self.shadow_softness = pcf;
303 }
304
305 pub fn light(&mut self, l: Light) {
310 self.lights[self.light_index] = l;
311 self.light_index = (self.light_index + 1) % 4;
312 }
313
314 pub fn ambient(&mut self, color: impl Into<Rgbf>, brightness: f32) {
316 self.ambient = Vec3::from(color.into()) * brightness;
317 }
318
319 pub fn exposure(&mut self, e: f32) {
321 self.exposure = e;
322 }
323
324 pub fn stroke_weight(&mut self, w: f32) {
326 self.stroke_weight = w;
327 }
328
329 pub fn font_size(&mut self, s: u32) {
331 self.font_size = s;
332 }
333
334 pub fn border_mode(&mut self, mode: BorderMode) {
336 self.border_mode = mode;
337 }
338
339 pub fn shape_mode(&mut self, mode: ShapeMode) {
341 self.shape_mode = mode;
342 }
343
344 pub fn filter(&mut self, f: Filter) {
346 self.filter = f;
347 }
348
349 pub fn wrap(&mut self, w: Wrap) {
351 self.wrap = w;
352 }
353
354 pub fn transform(&mut self, matrix: impl Into<Mat4>) {
356 self.matrix = matrix.into() * self.matrix;
357 }
358
359 pub fn reset_transform(&mut self) {
361 self.matrix = Mat4::identity();
362 }
363
364 pub fn translate(&mut self, v: impl Into<Vec3>) {
366 self.matrix = Mat4::translation(v) * self.matrix;
367 }
368
369 pub fn translate_x(&mut self, x: f32) {
371 self.matrix = Mat4::translation(Vec3::right() * x) * self.matrix;
372 }
373
374 pub fn translate_y(&mut self, y: f32) {
376 self.matrix = Mat4::translation(Vec3::up() * y) * self.matrix;
377 }
378
379 pub fn translate_z(&mut self, z: f32) {
381 self.matrix = Mat4::translation(Vec3::forward() * z) * self.matrix;
382 }
383
384 pub fn scale(&mut self, v: impl Into<Vec3>) {
386 self.matrix = Mat4::scale(v) * self.matrix;
387 }
388
389 pub fn rotate(&mut self, q: impl Into<Quat>) {
391 self.matrix = Mat4::from(q.into()) * self.matrix;
392 }
393
394 pub fn rotate_x(&mut self, d: f32) {
398 self.matrix = Mat4::euler_rotation(d, 0.0, 0.0) * self.matrix;
399 }
400
401 pub fn rotate_y(&mut self, d: f32) {
405 self.matrix = Mat4::euler_rotation(0.0, d, 0.0) * self.matrix;
406 }
407
408 pub fn rotate_z(&mut self, d: f32) {
412 self.matrix = Mat4::euler_rotation(0.0, 0.0, d) * self.matrix;
413 }
414
415 pub fn line(&mut self, p1: impl Into<Vec2>, p2: impl Into<Vec2>) {
417 let weight = self.stroke_weight / 2.0;
418 self.path(&[p1.into(), p2.into()], false, weight, weight);
419 }
420
421 pub fn lines(&mut self, points: &[Vec2]) {
423 let weight = self.stroke_weight / 2.0;
424 self.path(points, false, weight, weight);
425 }
426
427 pub fn mesh(&mut self, mesh: &Handle<Mesh>) {
429 let unshaded = self.lights.iter().all(|l| l.is_none());
430
431 let order = MeshOrder {
432 mesh: mesh.clone(),
433 matrix: self.matrix,
434 color: self.tint,
435 shadows: self.shadows,
436 sampler_index: self.sampler_index(),
437 };
438
439 let shader = match &self.shader {
440 Some(s) => s,
441 None if unshaded => &self.builtins.unshaded_shader,
442 None => &self.builtins.pbr_shader,
443 };
444
445 let material = match &self.material {
446 Some(m) => m,
447 None => &self.builtins.white_material,
448 };
449
450 match self.mesh_orders.iter_mut().find(|so| &so.shader == shader) {
451 Some(so) => match so.orders.iter_mut().find(|mo| &mo.material == material) {
452 Some(mo) => mo.orders.push(order),
453 None => so.orders.push(MaterialOrder {
454 material: material.clone(),
455 orders: vec![order],
456 }),
457 },
458 None => self.mesh_orders.push(ShaderOrder {
459 shader: shader.clone(),
460 orders: vec![MaterialOrder {
461 material: material.clone(),
462 orders: vec![order],
463 }],
464 }),
465 }
466 }
467
468 pub fn wireframe(&mut self, mesh: &Handle<Mesh>) {
470 self.push();
471 self.shadows = false;
472 self.shader = Some(self.builtins.wireframe_shader.clone());
473 self.mesh(mesh);
474 self.pop();
475 }
476
477 pub fn cube(&mut self, scale: impl Into<Vec3>) {
479 self.push();
480 self.matrix *= Mat4::scale(scale);
481 let mesh = self.builtins.cube_mesh.clone();
482 self.mesh(&mesh);
483 self.pop();
484 }
485
486 pub fn sphere_uv(&mut self, scale: impl Into<Vec3>) {
488 self.push();
489 self.matrix *= Mat4::scale(scale);
490 let mesh = self.builtins.uv_sphere_mesh.clone();
491 self.mesh(&mesh);
492 self.pop();
493 }
494
495 pub fn sphere_ico(&mut self, scale: impl Into<Vec3>) {
497 self.push();
498 self.matrix *= Mat4::scale(scale);
499 let mesh = self.builtins.ico_sphere_mesh.clone();
500 self.mesh(&mesh);
501 self.pop();
502 }
503
504 pub fn plane(&mut self, scale: impl Into<Vec2>) {
506 self.push();
507 self.matrix *= Mat4::scale(Vec3::from((scale.into(), 1.0)));
508 let mesh = self.builtins.plane_mesh.clone();
509 self.mesh(&mesh);
510 self.pop();
511 }
512
513 pub fn surface(&mut self, shader: &Handle<Shader>) {
515 self.push();
516 self.shader = Some(shader.clone());
517 let mesh = self.builtins.surface_mesh.clone();
518 self.mesh(&mesh);
519 self.pop();
520 }
521
522 pub fn fullscreen(&mut self, canvas: &Handle<Canvas>) {
524 self.push();
525 self.shader = Some(self.builtins.fullscreen_shader.clone());
526 self.material = Some(canvas.read().material().clone());
527 let mesh = self.builtins.surface_mesh.clone();
528 self.mesh(&mesh);
529 self.pop();
530 }
531
532 pub fn model(&mut self, model: &Handle<Model>) {
534 for node in &model.read().nodes {
535 self.push();
536 self.model_node(node, self.matrix);
537 self.pop();
538 }
539 }
540
541 pub fn debug_line<V: Into<Vec3>>(&mut self, p1: V, p2: V) {
544 self.line_orders.push(LineOrder {
545 points: [self.matrix * p1.into(), self.matrix * p2.into()],
546 color: self.stroke,
547 });
548 }
549
550 pub fn debug_grid(&mut self) {
552 let size = 100;
553 let half = size / 2;
554 let width = 1.0;
555
556 self.push();
557 for x in -half..half {
558 let xx = x as f32 * width;
559 let z_min = -half as f32 * width;
560 let z_max = half as f32 * width;
561
562 let color = match x {
563 0 => "#0000fff0",
564 _ => "#85858585",
565 };
566
567 self.stroke(color);
568 self.debug_line([xx, 0.0, z_min], [xx, 0.0, z_max]);
569 }
570 for z in -half..half {
571 let zz = z as f32 * width;
572 let x_min = -half as f32 * width;
573 let x_max = half as f32 * width;
574
575 let color = match z {
576 0 => "#ff0000f0",
577 _ => "#85858585",
578 };
579
580 self.stroke(color);
581 self.debug_line([x_min, 0.0, zz], [x_max, 0.0, zz]);
582 }
583 self.pop();
584 }
585
586 pub fn text(&mut self, text: impl AsRef<str>, pos: impl Into<Vec2>) {
588 let mut position = pos.into();
589 let t = text.as_ref();
590 let font = self
591 .font
592 .as_ref()
593 .unwrap_or(&self.builtins.fira_font)
594 .read();
595
596 let w = self.text_width(t);
597 let h = self.text_height(t);
598
599 position.y += h - self.text_height("a");
600
601 position += match self.shape_mode {
602 ShapeMode::BottomLeft => Vec2::new(0.0, 0.0),
603 ShapeMode::BottomRight => Vec2::new(-w, 0.0),
604 ShapeMode::TopLeft => Vec2::new(0.0, -h),
605 ShapeMode::TopRight => Vec2::new(-w, -h),
606 ShapeMode::Center => Vec2::new(-w / 2.0, -h / 2.0),
607 };
608
609 let metrics = font.metrics().scaled(self.font_size);
610 let start_x = position.x;
611
612 for c in t.chars() {
613 if c == ' ' {
615 position.x += metrics.space_width;
616 continue;
617 }
618 if c == '\n' {
619 position.x = start_x;
620 position.y -= metrics.height + metrics.line_gap;
621 continue;
622 }
623
624 let data = font.char_data(c).scaled(self.font_size);
626 let bx = data.bounds.x;
627 let by = data.bounds.y;
628 let mut cp = position;
629 cp.x += data.bearing.x;
630 cp.y -= metrics.descender;
631 cp.y -= data.bearing.y;
632
633 let p1 = self.matrix * Vec3::new(cp.x, cp.y + by, 0.0);
635 let p2 = self.matrix * Vec3::new(cp.x + bx, cp.y + by, 0.0);
636 let p3 = self.matrix * Vec3::new(cp.x + bx, cp.y, 0.0);
637 let p4 = self.matrix * Vec3::new(cp.x, cp.y, 0.0);
638
639 let uv1 = Vec2::new(data.uvs.x, data.uvs.y);
640 let uv2 = Vec2::new(data.uvs.z, data.uvs.y);
641 let uv3 = Vec2::new(data.uvs.z, data.uvs.w);
642 let uv4 = Vec2::new(data.uvs.x, data.uvs.w);
643
644 self.char_orders.push(CharOrder {
646 points: [p1, p2, p3, p4],
647 uvs: [uv1, uv2, uv3, uv4],
648 color: self.stroke,
649 texture: font.texture().shader_index(),
650 });
651
652 position.x += data.advance;
653 }
654 }
655
656 pub fn shape(&mut self, points: &[Vec2]) {
660 if points.len() < 3 {
662 return;
663 }
664
665 if self.fill.a > 0 {
667 let texture = self.builtins.white_texture.read().shader_index();
668 let opaque = self.fill.a == 255;
669
670 let first = Vec3::from((points[0], 0.0));
672 for i in 2..points.len() {
673 self.tri_orders.push(TriOrder {
674 points: [
675 self.matrix * first,
676 self.matrix * Vec3::from((points[i - 1], 0.0)),
677 self.matrix * Vec3::from((points[i], 0.0)),
678 ],
679 uvs: [Vec2::default(); 3],
680 color: self.fill,
681 sampler_index: 0,
682 texture,
683 opaque,
684 });
685 }
686 }
687
688 if self.stroke.a > 0 {
690 let outer_weight = match self.border_mode {
691 BorderMode::Center => self.stroke_weight / 2.0,
692 BorderMode::Outside => self.stroke_weight,
693 BorderMode::Inside => 0.0,
694 };
695 let inner_weight = match self.border_mode {
696 BorderMode::Center => self.stroke_weight / 2.0,
697 BorderMode::Outside => 0.0,
698 BorderMode::Inside => self.stroke_weight,
699 };
700
701 self.path(points, true, inner_weight, outer_weight);
702 }
703 }
704
705 pub fn rect(&mut self, pos: impl Into<Vec2>, size: impl Into<Vec2>) {
707 let s = size.into();
708 let p = pos.into();
709
710 let offset = match self.shape_mode {
711 ShapeMode::BottomLeft => Vec2::new(0.0, 0.0),
712 ShapeMode::BottomRight => Vec2::new(-s.x, 0.0),
713 ShapeMode::TopLeft => Vec2::new(0.0, -s.y),
714 ShapeMode::TopRight => Vec2::new(-s.x, -s.y),
715 ShapeMode::Center => Vec2::new(-s.x / 2.0, -s.y / 2.0),
716 };
717
718 self.shape(&[
719 Vec2::new(p.x, p.y + s.y) + offset,
720 Vec2::new(p.x + s.x, p.y + s.y) + offset,
721 Vec2::new(p.x + s.x, p.y) + offset,
722 Vec2::new(p.x, p.y) + offset,
723 ]);
724 }
725
726 pub fn square(&mut self, pos: impl Into<Vec2>, size: f32) {
728 self.rect(pos, Vec2::new(size, size));
729 }
730
731 pub fn ellipse(&mut self, pos: impl Into<Vec2>, size: impl Into<Vec2>) {
733 let s = size.into() / 2.0;
734 let side_count = (s.length() * 3.0) as u32;
735 let position = pos.into();
736
737 let offset = match self.shape_mode {
738 ShapeMode::BottomLeft => s,
739 ShapeMode::BottomRight => Vec2::new(-s.x, s.y),
740 ShapeMode::TopLeft => Vec2::new(s.x, -s.y),
741 ShapeMode::TopRight => Vec2::new(-s.x, -s.y),
742 ShapeMode::Center => Vec2::new(0.0, 0.0),
743 };
744
745 let points: Vec<_> = (0..side_count)
746 .map(|i| {
747 let q = 2.0 * PI * (i as f32 / side_count as f32);
748 let x = s.x * q.cos();
749 let y = s.y * q.sin();
750 position + offset + Vec2::new(x, y)
751 })
752 .collect();
753 self.shape(&points);
754 }
755
756 pub fn circle(&mut self, pos: impl Into<Vec2>, size: f32) {
758 self.ellipse(pos, Vec2::new(size, size));
759 }
760
761 pub fn texture(
763 &mut self,
764 texture: &Handle<Texture>,
765 pos: impl Into<Vec2>,
766 size: impl Into<Vec2>,
767 ) {
768 let (tw, th) = {
769 let tex = texture.read();
770 (tex.width() as f32, tex.height() as f32)
771 };
772 self.texture_part(texture, pos, size, [0.0, 0.0], [tw, th]);
773 }
774
775 pub fn texture_part(
779 &mut self,
780 texture: &Handle<Texture>,
781 pos: impl Into<Vec2>,
782 size: impl Into<Vec2>,
783 part_pos: impl Into<Vec2>,
784 part_size: impl Into<Vec2>,
785 ) {
786 let s = size.into();
787 let p = pos.into();
788 let pp = part_pos.into();
789 let ps = part_size.into();
790 let tex = texture.read();
791 let tw = tex.width() as f32;
792 let th = tex.height() as f32;
793 let opaque = tex.opaque() && self.tint.a == 255;
794
795 let offset = match self.shape_mode {
796 ShapeMode::BottomLeft => Vec3::new(0.0, 0.0, 0.0),
797 ShapeMode::BottomRight => Vec3::new(-s.x, 0.0, 0.0),
798 ShapeMode::TopLeft => Vec3::new(0.0, -s.y, 0.0),
799 ShapeMode::TopRight => Vec3::new(-s.x, -s.y, 0.0),
800 ShapeMode::Center => Vec3::new(-s.x / 2.0, -s.y / 2.0, 0.0),
801 };
802
803 let p1 = self.matrix * (Vec3::new(p.x, p.y + s.y, 0.0) + offset);
804 let p2 = self.matrix * (Vec3::new(p.x + s.x, p.y + s.y, 0.0) + offset);
805 let p3 = self.matrix * (Vec3::new(p.x + s.x, p.y, 0.0) + offset);
806 let p4 = self.matrix * (Vec3::new(p.x, p.y, 0.0) + offset);
807
808 let uv1 = Vec2::new(pp.x / tw, pp.y / th);
809 let uv2 = Vec2::new((pp.x + ps.x) / tw, pp.y / th);
810 let uv3 = Vec2::new((pp.x + ps.x) / tw, (pp.y + ps.y) / th);
811 let uv4 = Vec2::new(pp.x / tw, (pp.y + ps.y) / th);
812
813 self.tri_orders.push(TriOrder {
814 points: [p1, p2, p3],
815 color: self.tint,
816 uvs: [uv1, uv2, uv3],
817 texture: tex.shader_index(),
818 sampler_index: self.sampler_index(),
819 opaque,
820 });
821 self.tri_orders.push(TriOrder {
822 points: [p1, p3, p4],
823 color: self.tint,
824 uvs: [uv1, uv3, uv4],
825 texture: tex.shader_index(),
826 sampler_index: self.sampler_index(),
827 opaque,
828 });
829 }
830
831 pub fn text_width(&self, text: impl AsRef<str>) -> f32 {
833 let font = self
834 .font
835 .as_ref()
836 .unwrap_or(&self.builtins.fira_font)
837 .read();
838 let metrics = font.metrics().scaled(self.font_size);
839 let mut max_width = 0.0;
840
841 for line in text.as_ref().lines() {
843 let mut width = 0.0;
844 for c in line.chars() {
845 if c == ' ' {
847 width += metrics.space_width;
848 continue;
849 }
850 let data = font.char_data(c).scaled(self.font_size);
851 width += data.advance;
852 }
853 if width > max_width {
854 max_width = width;
855 }
856 }
857
858 max_width
859 }
860
861 pub fn text_height(&self, text: impl AsRef<str>) -> f32 {
863 let font = self
864 .font
865 .as_ref()
866 .unwrap_or(&self.builtins.fira_font)
867 .read();
868 let metrics = font.metrics().scaled(self.font_size);
869 let lines = text.as_ref().lines().count();
870 (metrics.height + metrics.line_gap) * lines as f32
871 }
872
873 pub fn push(&mut self) {
875 self.cache.push(Cache {
876 shader: self.shader.clone(),
877 material: self.material.clone(),
878 font: self.font.clone(),
879
880 background: self.background,
881 fill: self.fill,
882 stroke: self.stroke,
883 tint: self.tint,
884
885 shadows: self.shadows,
886
887 matrix: self.matrix,
888 stroke_weight: self.stroke_weight,
889 font_size: self.font_size,
890 shape_mode: self.shape_mode,
891 border_mode: self.border_mode,
892 filter: self.filter,
893 wrap: self.wrap,
894 });
895 }
896
897 pub fn pop(&mut self) {
899 if let Some(cache) = self.cache.pop() {
900 self.shader = cache.shader;
901 self.material = cache.material;
902 self.font = cache.font;
903
904 self.background = cache.background;
905 self.fill = cache.fill;
906 self.stroke = cache.stroke;
907 self.tint = cache.tint;
908
909 self.shadows = cache.shadows;
910
911 self.matrix = cache.matrix;
912 self.stroke_weight = cache.stroke_weight;
913 self.font_size = cache.font_size;
914 self.shape_mode = cache.shape_mode;
915 self.border_mode = cache.border_mode;
916 self.filter = cache.filter;
917 self.wrap = cache.wrap;
918 }
919 }
920
921 fn model_node(&mut self, node: &ModelNode, parent: Mat4) {
922 self.matrix = parent * node.matrix;
923 for (mesh, material) in node.orders() {
926 self.material(material);
927 self.mesh(mesh);
928 }
929
930 for child in &node.children {
931 self.push();
932 self.model_node(child, self.matrix);
933 self.pop();
934 }
935 }
936
937 fn path(&mut self, path: &[Vec2], closed: bool, inner_weight: f32, outer_weight: f32) {
938 let mut normals = vec![];
940
941 let mut points = path.to_vec();
942 if closed {
943 points.push(path[0]);
944 }
945
946 for i in 1..points.len() {
947 let prev = points[i - 1];
948 let curr = points[i];
949 let next = points.get(i + 1);
950
951 let line_a = (curr - prev).unit();
952
953 if i == 1 {
954 normals.push(line_a.normal());
956 }
957
958 if let Some(n) = next {
959 let line_b = (*n - curr).unit();
960 normals.push(miter(line_a, line_b));
961 } else {
962 normals.push(line_a.normal());
964 }
965 }
966
967 if points.len() > 2 && closed {
968 let prev = points[points.len() - 2];
970 let curr = points[0];
971 let next = points[1];
972
973 let line_a = (curr - prev).unit();
974 let line_b = (next - curr).unit();
975
976 let m = miter(line_a, line_b);
977 normals[0] = m;
978 normals[points.len() - 1] = m;
979 }
980
981 for i in 0..(normals.len() - 1) {
983 let curr_norm = normals[i];
984 let next_norm = normals[i + 1];
985 let curr_point = points[i];
986 let next_point = *points.get(i + 1).unwrap_or(&points[0]);
987
988 let p1 = self.matrix * Vec3::from((curr_point + curr_norm * outer_weight, -0.00001));
989 let p2 = self.matrix * Vec3::from((next_point + next_norm * outer_weight, -0.00001));
990 let p3 = self.matrix * Vec3::from((next_point - next_norm * inner_weight, -0.00001));
991 let p4 = self.matrix * Vec3::from((curr_point - curr_norm * inner_weight, -0.00001));
992
993 let texture = self.builtins.white_texture.read().shader_index();
994
995 self.tri_orders.push(TriOrder {
996 points: [p1, p2, p3],
997 color: self.stroke,
998 uvs: [Vec2::default(); 3],
999 opaque: self.stroke.a == 255,
1000 sampler_index: 0,
1001 texture,
1002 });
1003 self.tri_orders.push(TriOrder {
1004 points: [p1, p3, p4],
1005 color: self.stroke,
1006 uvs: [Vec2::default(); 3],
1007 opaque: self.stroke.a == 255,
1008 sampler_index: 0,
1009 texture,
1010 });
1011 }
1012 }
1013
1014 const fn sampler_index(&self) -> u32 {
1015 match (self.filter, self.wrap) {
1016 (Filter::Linear, Wrap::Repeat) => 0,
1017 (Filter::Linear, Wrap::ClampBorder) => 1,
1018 (Filter::Linear, Wrap::ClampEdge) => 2,
1019 (Filter::Nearest, Wrap::Repeat) => 3,
1020 (Filter::Nearest, Wrap::ClampBorder) => 4,
1021 (Filter::Nearest, Wrap::ClampEdge) => 5,
1022 }
1023 }
1024}
1025
1026fn miter(line_a: Vec2, line_b: Vec2) -> Vec2 {
1027 let tangent = (line_a + line_b).unit();
1028 let miter = tangent.normal();
1029 let norm_a = line_a.normal();
1030 let miter_len = 1.0 / miter.dot(norm_a);
1031
1032 miter * miter_len
1033}