1use crate::basics::{is_close, is_end_poly, is_move_to, is_stop, VertexSource};
10use crate::line_aa_basics::*;
11use crate::renderer_outline_aa::OutlineAaRenderer;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum OutlineAaJoin {
16 NoJoin,
17 Miter,
18 Round,
19 MiterAccurate,
20}
21
22#[derive(Debug, Clone, Copy)]
25pub struct LineAaVertex {
26 pub x: i32,
27 pub y: i32,
28 pub len: i32,
29}
30
31impl LineAaVertex {
32 pub fn new(x: i32, y: i32) -> Self {
33 Self { x, y, len: 0 }
34 }
35
36 pub fn calc_distance(&mut self, other: &LineAaVertex) -> bool {
40 let dx = (other.x - self.x) as f64;
41 let dy = (other.y - self.y) as f64;
42 self.len = (dx * dx + dy * dy).sqrt().round() as i32;
43 self.len > (LINE_SUBPIXEL_SCALE + LINE_SUBPIXEL_SCALE / 2)
44 }
45}
46
47struct VertexSeq {
54 data: Vec<LineAaVertex>,
55}
56
57impl VertexSeq {
58 fn new() -> Self {
59 Self { data: Vec::new() }
60 }
61
62 fn size(&self) -> usize {
63 self.data.len()
64 }
65
66 fn remove_all(&mut self) {
67 self.data.clear();
68 }
69
70 fn add(&mut self, val: LineAaVertex) {
73 if self.data.len() > 1 {
74 let n = self.data.len();
75 let last = self.data[n - 1];
76 if !self.data[n - 2].calc_distance(&last) {
77 self.data.pop();
78 }
79 }
80 self.data.push(val);
81 }
82
83 fn modify_last(&mut self, val: LineAaVertex) {
86 if !self.data.is_empty() {
87 self.data.pop();
88 }
89 self.add(val);
90 }
91
92 fn close(&mut self, closed: bool) {
95 while self.data.len() > 1 {
97 let n = self.data.len();
98 let last = self.data[n - 1];
99 if self.data[n - 2].calc_distance(&last) {
100 break;
101 }
102 let t = self.data.pop().unwrap();
103 self.modify_last(t);
104 }
105
106 if closed {
108 while self.data.len() > 1 {
109 let n = self.data.len();
110 let first = self.data[0];
111 if self.data[n - 1].calc_distance(&first) {
112 break;
113 }
114 self.data.pop();
115 }
116 }
117 }
118
119 fn get(&self, idx: usize) -> &LineAaVertex {
120 &self.data[idx]
121 }
122}
123
124impl std::ops::Index<usize> for VertexSeq {
125 type Output = LineAaVertex;
126 fn index(&self, idx: usize) -> &LineAaVertex {
127 &self.data[idx]
128 }
129}
130
131struct DrawVars {
136 idx: usize,
137 x1: i32,
138 y1: i32,
139 x2: i32,
140 y2: i32,
141 curr: LineParameters,
142 next: LineParameters,
143 lcurr: i32,
144 lnext: i32,
145 xb1: i32,
146 yb1: i32,
147 xb2: i32,
148 yb2: i32,
149 flags: u32,
150}
151
152pub struct RasterizerOutlineAa {
162 src_vertices: VertexSeq,
163 line_join: OutlineAaJoin,
164 round_cap: bool,
165 start_x: i32,
166 start_y: i32,
167}
168
169impl RasterizerOutlineAa {
170 pub fn new() -> Self {
171 Self {
172 src_vertices: VertexSeq::new(),
173 line_join: OutlineAaJoin::NoJoin,
174 round_cap: false,
175 start_x: 0,
176 start_y: 0,
177 }
178 }
179
180 pub fn set_line_join(&mut self, join: OutlineAaJoin) {
181 self.line_join = join;
182 }
183
184 pub fn line_join(&self) -> OutlineAaJoin {
185 self.line_join
186 }
187
188 pub fn set_round_cap(&mut self, v: bool) {
189 self.round_cap = v;
190 }
191
192 pub fn round_cap(&self) -> bool {
193 self.round_cap
194 }
195
196 pub fn move_to(&mut self, x: i32, y: i32) {
197 self.start_x = x;
198 self.start_y = y;
199 self.src_vertices.modify_last(LineAaVertex::new(x, y));
200 }
201
202 pub fn line_to(&mut self, x: i32, y: i32) {
203 self.src_vertices.add(LineAaVertex::new(x, y));
204 }
205
206 pub fn move_to_d(&mut self, x: f64, y: f64) {
207 self.move_to(line_coord(x), line_coord(y));
208 }
209
210 pub fn line_to_d(&mut self, x: f64, y: f64) {
211 self.line_to(line_coord(x), line_coord(y));
212 }
213
214 fn add_vertex<R: OutlineAaRenderer>(
216 &mut self,
217 x: f64,
218 y: f64,
219 cmd: u32,
220 ren: &mut R,
221 ) {
222 if is_move_to(cmd) {
223 self.render(ren, false);
224 self.move_to_d(x, y);
225 } else if is_end_poly(cmd) {
226 self.render(ren, is_close(cmd));
227 if is_close(cmd) {
228 self.move_to(self.start_x, self.start_y);
229 }
230 } else {
231 self.line_to_d(x, y);
232 }
233 }
234
235 pub fn add_path<VS: VertexSource, R: OutlineAaRenderer>(
237 &mut self,
238 vs: &mut VS,
239 path_id: u32,
240 ren: &mut R,
241 ) {
242 vs.rewind(path_id);
243 let (mut x, mut y) = (0.0, 0.0);
244 loop {
245 let cmd = vs.vertex(&mut x, &mut y);
246 if is_stop(cmd) {
247 break;
248 }
249 self.add_vertex(x, y, cmd, ren);
250 }
251 self.render(ren, false);
253 }
254
255 fn draw<R: OutlineAaRenderer>(
260 &self,
261 dv: &mut DrawVars,
262 start: usize,
263 end: usize,
264 ren: &mut R,
265 ) {
266 for _i in start..end {
267 if self.line_join == OutlineAaJoin::Round {
268 dv.xb1 = dv.curr.x1 + (dv.curr.y2 - dv.curr.y1);
269 dv.yb1 = dv.curr.y1 - (dv.curr.x2 - dv.curr.x1);
270 dv.xb2 = dv.curr.x2 + (dv.curr.y2 - dv.curr.y1);
271 dv.yb2 = dv.curr.y2 - (dv.curr.x2 - dv.curr.x1);
272 }
273
274 match dv.flags {
275 0 => ren.line3(&dv.curr, dv.xb1, dv.yb1, dv.xb2, dv.yb2),
276 1 => ren.line2(&dv.curr, dv.xb2, dv.yb2),
277 2 => ren.line1(&dv.curr, dv.xb1, dv.yb1),
278 _ => ren.line0(&dv.curr),
279 }
280
281 if self.line_join == OutlineAaJoin::Round && (dv.flags & 2) == 0 {
282 ren.pie(
283 dv.curr.x2,
284 dv.curr.y2,
285 dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
286 dv.curr.y2 - (dv.curr.x2 - dv.curr.x1),
287 dv.curr.x2 + (dv.next.y2 - dv.next.y1),
288 dv.curr.y2 - (dv.next.x2 - dv.next.x1),
289 );
290 }
291
292 dv.x1 = dv.x2;
293 dv.y1 = dv.y2;
294 dv.lcurr = dv.lnext;
295 dv.lnext = self.src_vertices[dv.idx].len;
296
297 dv.idx += 1;
298 if dv.idx >= self.src_vertices.size() {
299 dv.idx = 0;
300 }
301
302 let v = self.src_vertices.get(dv.idx);
303 dv.x2 = v.x;
304 dv.y2 = v.y;
305
306 dv.curr = dv.next;
307 dv.next = LineParameters::new(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
308 dv.xb1 = dv.xb2;
309 dv.yb1 = dv.yb2;
310
311 match self.line_join {
312 OutlineAaJoin::NoJoin => {
313 dv.flags = 3;
314 }
315 OutlineAaJoin::Miter => {
316 dv.flags >>= 1;
317 dv.flags |= if dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant() {
318 2
319 } else {
320 0
321 };
322 if (dv.flags & 2) == 0 {
323 bisectrix(&dv.curr, &dv.next, &mut dv.xb2, &mut dv.yb2);
324 }
325 }
326 OutlineAaJoin::Round => {
327 dv.flags >>= 1;
328 dv.flags |= if dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant() {
329 2
330 } else {
331 0
332 };
333 }
334 OutlineAaJoin::MiterAccurate => {
335 dv.flags = 0;
336 bisectrix(&dv.curr, &dv.next, &mut dv.xb2, &mut dv.yb2);
337 }
338 }
339 }
340 }
341
342 pub fn render<R: OutlineAaRenderer>(
347 &mut self,
348 ren: &mut R,
349 close_polygon: bool,
350 ) {
351 self.src_vertices.close(close_polygon);
352
353 let saved_join = self.line_join;
358 if ren.accurate_join_only() {
359 self.line_join = OutlineAaJoin::MiterAccurate;
360 }
361
362 if close_polygon {
363 if self.src_vertices.size() >= 3 {
365 let mut dv = DrawVars {
366 idx: 2,
367 x1: 0, y1: 0, x2: 0, y2: 0,
368 curr: LineParameters::new(0, 0, 1, 0, 1), next: LineParameters::new(0, 0, 1, 0, 1),
370 lcurr: 0, lnext: 0,
371 xb1: 0, yb1: 0, xb2: 0, yb2: 0,
372 flags: 0,
373 };
374
375 let n = self.src_vertices.size();
376
377 let v_last = self.src_vertices[n - 1];
378 let x1 = v_last.x;
379 let y1 = v_last.y;
380 let lprev = v_last.len;
381
382 let v0 = self.src_vertices[0];
383 let x2 = v0.x;
384 let y2 = v0.y;
385 dv.lcurr = v0.len;
386 let prev = LineParameters::new(x1, y1, x2, y2, lprev);
387
388 let v1 = self.src_vertices[1];
389 dv.x1 = v1.x;
390 dv.y1 = v1.y;
391 dv.lnext = v1.len;
392 dv.curr = LineParameters::new(x2, y2, dv.x1, dv.y1, dv.lcurr);
393
394 let v2 = self.src_vertices[dv.idx];
395 dv.x2 = v2.x;
396 dv.y2 = v2.y;
397 dv.next = LineParameters::new(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
398
399 match self.line_join {
400 OutlineAaJoin::NoJoin => {
401 dv.flags = 3;
402 }
403 OutlineAaJoin::Miter | OutlineAaJoin::Round => {
404 let f1 = if prev.diagonal_quadrant() == dv.curr.diagonal_quadrant() { 1 } else { 0 };
405 let f2 = if dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant() { 2 } else { 0 };
406 dv.flags = f1 | f2;
407 }
408 OutlineAaJoin::MiterAccurate => {
409 dv.flags = 0;
410 }
411 }
412
413 if (dv.flags & 1) == 0 && self.line_join != OutlineAaJoin::Round {
414 bisectrix(&prev, &dv.curr, &mut dv.xb1, &mut dv.yb1);
415 }
416 if (dv.flags & 2) == 0 && self.line_join != OutlineAaJoin::Round {
417 bisectrix(&dv.curr, &dv.next, &mut dv.xb2, &mut dv.yb2);
418 }
419
420 self.draw(&mut dv, 0, n, ren);
421 }
422 } else {
423 let n = self.src_vertices.size();
425
426 match n {
427 0 | 1 => {} 2 => {
429 let v0 = self.src_vertices[0];
430 let x1 = v0.x;
431 let y1 = v0.y;
432 let lprev = v0.len;
433 let v1 = self.src_vertices[1];
434 let x2 = v1.x;
435 let y2 = v1.y;
436 let lp = LineParameters::new(x1, y1, x2, y2, lprev);
437
438 if self.round_cap {
439 ren.semidot(
440 cmp_dist_start,
441 x1, y1,
442 x1 + (y2 - y1), y1 - (x2 - x1),
443 );
444 }
445 ren.line3(
446 &lp,
447 x1 + (y2 - y1), y1 - (x2 - x1),
448 x2 + (y2 - y1), y2 - (x2 - x1),
449 );
450 if self.round_cap {
451 ren.semidot(
452 cmp_dist_end,
453 x2, y2,
454 x2 + (y2 - y1), y2 - (x2 - x1),
455 );
456 }
457 }
458 3 => {
459 let v0 = self.src_vertices[0];
460 let x1 = v0.x;
461 let y1 = v0.y;
462 let lprev = v0.len;
463 let v1 = self.src_vertices[1];
464 let x2 = v1.x;
465 let y2 = v1.y;
466 let lnext = v1.len;
467 let v2 = self.src_vertices[2];
468 let x3 = v2.x;
469 let y3 = v2.y;
470 let lp1 = LineParameters::new(x1, y1, x2, y2, lprev);
471 let lp2 = LineParameters::new(x2, y2, x3, y3, lnext);
472
473 if self.round_cap {
474 ren.semidot(
475 cmp_dist_start,
476 x1, y1,
477 x1 + (y2 - y1), y1 - (x2 - x1),
478 );
479 }
480
481 if self.line_join == OutlineAaJoin::Round {
482 ren.line3(
483 &lp1,
484 x1 + (y2 - y1), y1 - (x2 - x1),
485 x2 + (y2 - y1), y2 - (x2 - x1),
486 );
487 ren.pie(
488 x2, y2,
489 x2 + (y2 - y1), y2 - (x2 - x1),
490 x2 + (y3 - y2), y2 - (x3 - x2),
491 );
492 ren.line3(
493 &lp2,
494 x2 + (y3 - y2), y2 - (x3 - x2),
495 x3 + (y3 - y2), y3 - (x3 - x2),
496 );
497 } else {
498 let (mut xb1, mut yb1) = (0i32, 0i32);
499 bisectrix(&lp1, &lp2, &mut xb1, &mut yb1);
500 ren.line3(
501 &lp1,
502 x1 + (y2 - y1), y1 - (x2 - x1),
503 xb1, yb1,
504 );
505 ren.line3(
506 &lp2,
507 xb1, yb1,
508 x3 + (y3 - y2), y3 - (x3 - x2),
509 );
510 }
511
512 if self.round_cap {
513 ren.semidot(
514 cmp_dist_end,
515 x3, y3,
516 x3 + (y3 - y2), y3 - (x3 - x2),
517 );
518 }
519 }
520 _ => {
521 let mut dv = DrawVars {
523 idx: 3,
524 x1: 0, y1: 0, x2: 0, y2: 0,
525 curr: LineParameters::new(0, 0, 1, 0, 1),
526 next: LineParameters::new(0, 0, 1, 0, 1),
527 lcurr: 0, lnext: 0,
528 xb1: 0, yb1: 0, xb2: 0, yb2: 0,
529 flags: 0,
530 };
531
532 let v0 = self.src_vertices[0];
533 let x1 = v0.x;
534 let y1 = v0.y;
535 let lprev = v0.len;
536
537 let v1 = self.src_vertices[1];
538 let x2 = v1.x;
539 let y2 = v1.y;
540 dv.lcurr = v1.len;
541 let prev = LineParameters::new(x1, y1, x2, y2, lprev);
542
543 let v2 = self.src_vertices[2];
544 dv.x1 = v2.x;
545 dv.y1 = v2.y;
546 dv.lnext = v2.len;
547 dv.curr = LineParameters::new(x2, y2, dv.x1, dv.y1, dv.lcurr);
548
549 let v3 = self.src_vertices[dv.idx];
550 dv.x2 = v3.x;
551 dv.y2 = v3.y;
552 dv.next = LineParameters::new(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
553
554 match self.line_join {
555 OutlineAaJoin::NoJoin => {
556 dv.flags = 3;
557 }
558 OutlineAaJoin::Miter | OutlineAaJoin::Round => {
559 let f1 = if prev.diagonal_quadrant() == dv.curr.diagonal_quadrant() { 1 } else { 0 };
560 let f2 = if dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant() { 2 } else { 0 };
561 dv.flags = f1 | f2;
562 }
563 OutlineAaJoin::MiterAccurate => {
564 dv.flags = 0;
565 }
566 }
567
568 if self.round_cap {
570 ren.semidot(
571 cmp_dist_start,
572 x1, y1,
573 x1 + (y2 - y1), y1 - (x2 - x1),
574 );
575 }
576
577 if (dv.flags & 1) == 0 {
579 if self.line_join == OutlineAaJoin::Round {
580 ren.line3(
581 &prev,
582 x1 + (y2 - y1), y1 - (x2 - x1),
583 x2 + (y2 - y1), y2 - (x2 - x1),
584 );
585 ren.pie(
586 prev.x2, prev.y2,
587 x2 + (y2 - y1), y2 - (x2 - x1),
588 dv.curr.x1 + (dv.curr.y2 - dv.curr.y1),
589 dv.curr.y1 - (dv.curr.x2 - dv.curr.x1),
590 );
591 } else {
592 bisectrix(&prev, &dv.curr, &mut dv.xb1, &mut dv.yb1);
593 ren.line3(
594 &prev,
595 x1 + (y2 - y1), y1 - (x2 - x1),
596 dv.xb1, dv.yb1,
597 );
598 }
599 } else {
600 ren.line1(
601 &prev,
602 x1 + (y2 - y1), y1 - (x2 - x1),
603 );
604 }
605
606 if (dv.flags & 2) == 0 && self.line_join != OutlineAaJoin::Round {
607 bisectrix(&dv.curr, &dv.next, &mut dv.xb2, &mut dv.yb2);
608 }
609
610 self.draw(&mut dv, 1, n - 2, ren);
612
613 if (dv.flags & 1) == 0 {
615 if self.line_join == OutlineAaJoin::Round {
616 ren.line3(
617 &dv.curr,
618 dv.curr.x1 + (dv.curr.y2 - dv.curr.y1),
619 dv.curr.y1 - (dv.curr.x2 - dv.curr.x1),
620 dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
621 dv.curr.y2 - (dv.curr.x2 - dv.curr.x1),
622 );
623 } else {
624 ren.line3(
625 &dv.curr,
626 dv.xb1, dv.yb1,
627 dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
628 dv.curr.y2 - (dv.curr.x2 - dv.curr.x1),
629 );
630 }
631 } else {
632 ren.line2(
633 &dv.curr,
634 dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
635 dv.curr.y2 - (dv.curr.x2 - dv.curr.x1),
636 );
637 }
638
639 if self.round_cap {
641 ren.semidot(
642 cmp_dist_end,
643 dv.curr.x2, dv.curr.y2,
644 dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
645 dv.curr.y2 - (dv.curr.x2 - dv.curr.x1),
646 );
647 }
648 }
649 }
650 }
651 self.src_vertices.remove_all();
652 self.line_join = saved_join;
653 }
654}
655
656impl Default for RasterizerOutlineAa {
657 fn default() -> Self {
658 Self::new()
659 }
660}
661
662fn cmp_dist_start(dist: i32) -> bool {
665 dist > 0
666}
667
668fn cmp_dist_end(dist: i32) -> bool {
671 dist <= 0
672}
673
674
675#[cfg(test)]
676mod tests {
677 use super::*;
678 use crate::color::Rgba8;
679 use crate::pixfmt_rgba::PixfmtRgba32;
680 use crate::renderer_base::RendererBase;
681 use crate::renderer_outline_aa::{LineProfileAa, RendererOutlineAa};
682 use crate::rendering_buffer::RowAccessor;
683
684 fn make_buffer(w: u32, h: u32) -> (Vec<u8>, RowAccessor) {
685 let stride = (w * 4) as i32;
686 let buf = vec![0u8; (h * w * 4) as usize];
687 let mut ra = RowAccessor::new();
688 unsafe {
689 ra.attach(buf.as_ptr() as *mut u8, w, h, stride);
690 }
691 (buf, ra)
692 }
693
694 #[test]
695 fn test_rasterizer_creation() {
696 let ras = RasterizerOutlineAa::new();
697 assert_eq!(ras.line_join(), OutlineAaJoin::NoJoin);
698 assert!(!ras.round_cap());
699 }
700
701 fn scan_for_color(ren_aa: &RendererOutlineAa<PixfmtRgba32>, cx: i32, cy: i32, radius: i32, channel: &str) -> bool {
702 for y in (cy - radius)..=(cy + radius) {
703 for x in (cx - radius)..=(cx + radius) {
704 if x < 0 || y < 0 { continue; }
705 let p = ren_aa.ren().pixel(x, y);
706 match channel {
707 "r" => { if p.r > 0 { return true; } }
708 "g" => { if p.g > 0 { return true; } }
709 "b" => { if p.b > 0 { return true; } }
710 _ => {}
711 }
712 }
713 }
714 false
715 }
716
717 #[test]
718 fn test_rasterizer_two_points() {
719 let (_buf, mut ra) = make_buffer(100, 100);
720 let pixf = PixfmtRgba32::new(&mut ra);
721 let mut ren = RendererBase::new(pixf);
722 let prof = LineProfileAa::with_width(2.0);
723 let mut ren_aa = RendererOutlineAa::new(&mut ren, &prof);
724 ren_aa.set_color(Rgba8::new(255, 0, 0, 255));
725
726 let mut ras = RasterizerOutlineAa::new();
727 ras.move_to_d(10.0, 50.0);
728 ras.line_to_d(90.0, 50.0);
729 ras.render(&mut ren_aa, false);
730
731 assert!(scan_for_color(&ren_aa, 50, 50, 2, "r"), "Expected red pixels near (50,50)");
732 }
733
734 #[test]
735 fn test_rasterizer_polyline() {
736 let (_buf, mut ra) = make_buffer(100, 100);
737 let pixf = PixfmtRgba32::new(&mut ra);
738 let mut ren = RendererBase::new(pixf);
739 let prof = LineProfileAa::with_width(1.5);
740 let mut ren_aa = RendererOutlineAa::new(&mut ren, &prof);
741 ren_aa.set_color(Rgba8::new(0, 255, 0, 255));
742
743 let mut ras = RasterizerOutlineAa::new();
744 ras.set_line_join(OutlineAaJoin::Miter);
745 ras.move_to_d(10.0, 10.0);
746 ras.line_to_d(50.0, 50.0);
747 ras.line_to_d(90.0, 10.0);
748 ras.render(&mut ren_aa, false);
749
750 assert!(scan_for_color(&ren_aa, 50, 50, 2, "g"), "Expected green pixels near (50,50)");
751 }
752
753 #[test]
754 fn test_rasterizer_closed_polygon() {
755 let (_buf, mut ra) = make_buffer(100, 100);
756 let pixf = PixfmtRgba32::new(&mut ra);
757 let mut ren = RendererBase::new(pixf);
758 let prof = LineProfileAa::with_width(1.0);
759 let mut ren_aa = RendererOutlineAa::new(&mut ren, &prof);
760 ren_aa.set_color(Rgba8::new(0, 0, 255, 255));
761
762 let mut ras = RasterizerOutlineAa::new();
763 ras.move_to_d(20.0, 20.0);
764 ras.line_to_d(80.0, 20.0);
765 ras.line_to_d(80.0, 80.0);
766 ras.line_to_d(20.0, 80.0);
767 ras.render(&mut ren_aa, true);
768
769 assert!(scan_for_color(&ren_aa, 50, 20, 2, "b"), "Expected blue pixels near (50,20)");
770 }
771}