1#![allow(clippy::too_many_arguments)]
4
5use super::geometry::{Point, Vector};
6use super::path_builder::PathBuilder;
7use super::style::Fill;
8
9use crate::lib::Vec;
10use core::fmt;
11
12#[inline(always)]
13fn coverage(fill: Fill, mut coverage: i32) -> u8 {
14 coverage >>= PIXEL_BITS * 2 + 1 - 8;
15 if fill == Fill::EvenOdd {
16 coverage &= 511;
17 if coverage >= 256 {
18 coverage = 511i32.wrapping_sub(coverage);
19 }
20 } else {
21 if coverage < 0 {
22 coverage = !coverage;
23 }
24 if coverage >= 256 {
25 coverage = 255;
26 }
27 }
28 coverage as u8
29}
30
31pub struct Rasterizer<'a, S: RasterStorage> {
32 storage: &'a mut S,
33 xmin: i32,
34 xmax: i32,
35 ymin: i32,
36 ymax: i32,
37 height: i32,
38 shift: Vector,
39 start: FixedPoint,
40 closed: bool,
41 current: Point,
42 x: i32,
43 y: i32,
44 px: i32,
45 py: i32,
46 cover: i32,
47 area: i32,
48 invalid: bool,
49}
50
51impl<'a, S: RasterStorage> Rasterizer<'a, S> {
52 pub fn new(storage: &'a mut S) -> Self {
53 Self {
54 storage,
55 xmin: 0,
56 xmax: 0,
57 ymin: 0,
58 ymax: 0,
59 height: 0,
60 shift: Vector::ZERO,
61 start: FixedPoint::default(),
62 closed: false,
63 current: Point::ZERO,
64 x: 0,
65 y: 0,
66 px: 0,
67 py: 0,
68 cover: 0,
69 area: 0,
70 invalid: false,
71 }
72 }
73
74 pub fn rasterize(
75 &mut self,
76 shift: Vector,
77 width: u32,
78 height: u32,
79 apply: &mut impl FnMut(&mut Self),
80 fill: Fill,
81 buffer: &mut [u8],
82 pitch: usize,
83 y_up: bool,
84 ) {
85 let w = width as i32;
86 let h = height as i32;
87 self.storage
88 .reset(FixedPoint { x: 0, y: 0 }, FixedPoint { x: w, y: h });
89 self.shift = shift;
90 self.start = FixedPoint::default();
91 self.closed = true;
92 self.current = Point::ZERO;
93 self.xmin = 0;
94 self.ymin = 0;
95 self.xmax = w;
96 self.ymax = h;
97 self.height = h;
98 self.x = 0;
99 self.y = 0;
100 self.px = 0;
101 self.py = 0;
102 self.invalid = true;
103 apply(self);
104 if !self.closed {
105 self.line_to(self.start);
106 }
107 if !self.invalid {
108 self.storage.set(self.x, self.y, self.area, self.cover);
109 }
110 let indices = self.storage.indices();
111 let cells = self.storage.cells();
112 let min = FixedPoint::new(self.xmin, self.ymin);
113 let max = FixedPoint::new(self.xmax, self.ymax);
114 let height = height as usize;
115 for (i, &index) in indices.iter().enumerate() {
116 if index != -1 {
117 let y = ((i as i32) - min.y) as usize;
118 let row_offset = if y_up {
119 pitch * (height - 1 - y)
120 } else {
121 pitch * y
122 };
123 let row = &mut buffer[row_offset..];
124 let mut x = min.x;
125 let mut cover = 0;
126 let mut area;
127 let mut index = index;
128 loop {
129 let cell = &cells[index as usize];
130 if cover != 0 && cell.x > x {
131 let count = (cell.x - x) as usize;
132 let c = coverage(fill, cover);
133 let xi = x as usize;
134 for b in &mut row[xi..xi + count] {
135 *b = c;
136 }
137 }
138 cover = cover.wrapping_add(cell.cover.wrapping_mul(ONE_PIXEL * 2));
139 area = cover.wrapping_sub(cell.area);
140 if area != 0 && cell.x >= min.x {
141 let count = 1;
142 let c = coverage(fill, area);
143 let xi = cell.x as usize;
144 for b in &mut row[xi..xi + count] {
145 *b = c;
146 }
147 }
148 x = cell.x + 1;
149 index = cell.next;
150 if index == -1 {
151 break;
152 }
153 }
154 if cover != 0 {
155 let count = (max.x - x) as usize;
156 let c = coverage(fill, cover);
157 let xi = x as usize;
158 for b in &mut row[xi..xi + count] {
159 *b = c;
160 }
161 }
162 }
163 }
164 }
165
166 pub fn rasterize_write(
167 &mut self,
168 shift: Vector,
169 width: u32,
170 height: u32,
171 apply: &mut impl FnMut(&mut Self),
172 fill: Fill,
173 pitch: usize,
174 y_up: bool,
175 write: &mut impl FnMut(usize, usize, usize, u8),
176 ) {
177 let w = width as i32;
178 let h = height as i32;
179 self.storage
180 .reset(FixedPoint { x: 0, y: 0 }, FixedPoint { x: w, y: h });
181 self.shift = shift;
182 self.start = FixedPoint::default();
183 self.closed = true;
184 self.current = Point::ZERO;
185 self.xmin = 0;
186 self.ymin = 0;
187 self.xmax = w;
188 self.ymax = h;
189 self.height = h;
190 self.x = 0;
191 self.y = 0;
192 self.px = 0;
193 self.py = 0;
194 self.invalid = true;
195 apply(self);
196 if !self.closed {
197 self.line_to(self.start);
198 }
199 if !self.invalid {
200 self.storage.set(self.x, self.y, self.area, self.cover);
201 }
202 let indices = self.storage.indices();
203 let cells = self.storage.cells();
204 let min = FixedPoint::new(self.xmin, self.ymin);
205 let max = FixedPoint::new(self.xmax, self.ymax);
206 let height = height as usize;
207 for (i, &index) in indices.iter().enumerate() {
208 if index != -1 {
209 let y = ((i as i32) - min.y) as usize;
210 let row_offset = if y_up {
211 pitch * (height - 1 - y)
212 } else {
213 pitch * y
214 };
215 let mut x = min.x;
216 let mut cover = 0;
217 let mut area;
218 let mut index = index;
219 loop {
220 let cell = &cells[index as usize];
221 if cover != 0 && cell.x > x {
222 let count = (cell.x - x) as usize;
223 let c = coverage(fill, cover);
224 let xi = x as usize;
225 write(row_offset, xi, count, c);
226 }
227 cover = cover.wrapping_add(cell.cover.wrapping_mul(ONE_PIXEL * 2));
228 area = cover.wrapping_sub(cell.area);
229 if area != 0 && cell.x >= min.x {
230 let count = 1;
231 let c = coverage(fill, area);
232 let xi = cell.x as usize;
233 write(row_offset, xi, count, c);
234 }
235 x = cell.x + 1;
236 index = cell.next;
237 if index == -1 {
238 break;
239 }
240 }
241 if cover != 0 {
242 let count = (max.x - x) as usize;
243 let c = coverage(fill, cover);
244 let xi = x as usize;
245 write(row_offset, xi, count, c);
246 }
247 }
248 }
249 }
250
251 #[inline(always)]
252 fn set_cell(&mut self, x: i32, y: i32) {
253 if !self.invalid && (self.area != 0 || self.cover != 0) {
254 self.storage.set(self.x, self.y, self.area, self.cover);
255 }
256 self.area = 0;
257 self.cover = 0;
258 self.x = if x > (self.xmin - 1) {
259 x
260 } else {
261 self.xmin - 1
262 };
263 self.y = y;
264 self.invalid = y >= self.ymax || y < self.ymin || x >= self.xmax;
265 }
266
267 fn move_to(&mut self, to: FixedPoint) {
268 self.set_cell(trunc(to.x), trunc(to.y));
269 self.px = to.x;
270 self.py = to.y;
271 }
272
273 fn line_to(&mut self, to: FixedPoint) {
274 let to_x = to.x;
275 let to_y = to.y;
276 let mut ey1 = trunc(self.py);
277 let ey2 = trunc(to_y);
278 if (ey1 >= self.ymax && ey2 >= self.ymax) || (ey1 < self.ymin && ey2 < self.ymin) {
279 self.px = to_x;
280 self.py = to_y;
281 return;
282 }
283 let mut ex1 = trunc(self.px);
284 let ex2 = trunc(to_x);
285 let mut fx1 = fract(self.px);
286 let mut fy1 = fract(self.py);
287 let dx = to_x - self.px;
288 let dy = to_y - self.py;
289 if ex1 == ex2 && ey1 == ey2 {
290 } else if dy == 0 {
292 self.set_cell(ex2, ey2);
293 self.px = to_x;
294 self.py = to_y;
295 return;
296 } else if dx == 0 {
297 if dy > 0 {
298 loop {
299 let fy2 = ONE_PIXEL;
300 self.cover += fy2 - fy1;
301 self.area += (fy2 - fy1) * fx1 * 2;
302 fy1 = 0;
303 ey1 += 1;
304 self.set_cell(ex1, ey1);
305 if ey1 == ey2 {
306 break;
307 }
308 }
309 } else {
310 loop {
311 let fy2 = 0;
312 self.cover += fy2 - fy1;
313 self.area += (fy2 - fy1) * fx1 * 2;
314 fy1 = ONE_PIXEL;
315 ey1 -= 1;
316 self.set_cell(ex1, ey1);
317 if ey1 == ey2 {
318 break;
319 }
320 }
321 }
322 } else {
323 let mut prod = dx * fy1 - dy * fx1;
324 let dx_r = if ex1 != ex2 { (0x00FFFFFF) / dx } else { 0 };
325 let dy_r = if ey1 != ey2 { (0x00FFFFFF) / dy } else { 0 };
326 fn udiv(a: i32, b: i32) -> i32 {
327 ((a as u64 * b as u64) >> (4 * 8 - PIXEL_BITS)) as i32
328 }
329 loop {
330 if prod <= 0 && prod - dx * ONE_PIXEL > 0 {
331 let fx2 = 0;
332 let fy2 = udiv(-prod, -dx_r);
333 prod -= dy * ONE_PIXEL;
334 self.cover += fy2 - fy1;
335 self.area += (fy2 - fy1) * (fx1 + fx2);
336 fx1 = ONE_PIXEL;
337 fy1 = fy2;
338 ex1 -= 1;
339 } else if prod - dx * ONE_PIXEL <= 0 && prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 {
340 prod -= dx * ONE_PIXEL;
341 let fx2 = udiv(-prod, dy_r);
342 let fy2 = ONE_PIXEL;
343 self.cover += fy2 - fy1;
344 self.area += (fy2 - fy1) * (fx1 + fx2);
345 fx1 = fx2;
346 fy1 = 0;
347 ey1 += 1;
348 } else if prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 && prod + dy * ONE_PIXEL >= 0
349 {
350 prod += dy * ONE_PIXEL;
351 let fx2 = ONE_PIXEL;
352 let fy2 = udiv(prod, dx_r);
353 self.cover += fy2 - fy1;
354 self.area += (fy2 - fy1) * (fx1 + fx2);
355 fx1 = 0;
356 fy1 = fy2;
357 ex1 += 1;
358 } else {
359 let fx2 = udiv(prod, -dy_r);
360 let fy2 = 0;
361 prod += dx * ONE_PIXEL;
362 self.cover += fy2 - fy1;
363 self.area += (fy2 - fy1) * (fx1 + fx2);
364 fx1 = fx2;
365 fy1 = ONE_PIXEL;
366 ey1 -= 1;
367 }
368 self.set_cell(ex1, ey1);
369 if ex1 == ex2 && ey1 == ey2 {
370 break;
371 }
372 }
373 }
374 let fx2 = fract(to_x);
375 let fy2 = fract(to_y);
376 self.cover += fy2 - fy1;
377 self.area += (fy2 - fy1) * (fx1 + fx2);
378 self.px = to_x;
379 self.py = to_y;
380 }
381
382 #[allow(clippy::uninit_assumed_init, invalid_value)]
383 fn quad_to(&mut self, control: FixedPoint, to: FixedPoint) {
384 let mut arc = [FixedPoint::default(); 16 * 2 + 1];
385 arc[0].x = to.x;
386 arc[0].y = to.y;
387 arc[1].x = control.x;
388 arc[1].y = control.y;
389 arc[2].x = self.px;
390 arc[2].y = self.py;
391 if (trunc(arc[0].y) >= self.ymax
392 && trunc(arc[1].y) >= self.ymax
393 && trunc(arc[2].y) >= self.ymax)
394 || (trunc(arc[0].y) < self.ymin
395 && trunc(arc[1].y) < self.ymin
396 && trunc(arc[2].y) < self.ymin)
397 {
398 self.px = arc[0].x;
399 self.py = arc[0].y;
400 return;
401 }
402 let mut dx = (arc[2].x + arc[0].x - 2 * arc[1].x).abs();
403 let dy = (arc[2].y + arc[0].y - 2 * arc[1].y).abs();
404 if dx < dy {
405 dx = dy;
406 }
407 let mut draw = 1;
408 while dx > ONE_PIXEL / 4 {
409 dx >>= 2;
410 draw <<= 1;
411 }
412 let mut a = 0;
413 loop {
414 let mut split = draw & (-draw);
415 loop {
416 split >>= 1;
417 if split == 0 {
418 break;
419 }
420 split_quad(&mut arc[a..]);
421 a += 2;
422 }
423 let p = arc[a];
424 self.line_to(p);
425 draw -= 1;
426 if draw == 0 {
427 break;
428 }
429 a -= 2;
430 }
431 }
432
433 #[allow(clippy::uninit_assumed_init, invalid_value)]
434 fn curve_to(&mut self, control1: FixedPoint, control2: FixedPoint, to: FixedPoint) {
435 let mut arc = [FixedPoint::default(); 16 * 8 + 1];
436 arc[0].x = to.x;
437 arc[0].y = to.y;
438 arc[1].x = control2.x;
439 arc[1].y = control2.y;
440 arc[2].x = control1.x;
441 arc[2].y = control1.y;
442 arc[3].x = self.px;
443 arc[3].y = self.py;
444 if (trunc(arc[0].y) >= self.ymax
445 && trunc(arc[1].y) >= self.ymax
446 && trunc(arc[2].y) >= self.ymax
447 && trunc(arc[3].y) >= self.ymax)
448 || (trunc(arc[0].y) < self.ymin
449 && trunc(arc[1].y) < self.ymin
450 && trunc(arc[2].y) < self.ymin
451 && trunc(arc[3].y) < self.ymin)
452 {
453 self.px = arc[0].x;
454 self.py = arc[0].y;
455 return;
456 }
457 let mut a = 0;
458 loop {
459 if (2 * arc[a].x - 3 * arc[a + 1].x + arc[a + 3].x).abs() > ONE_PIXEL / 2
460 || (2 * arc[a].y - 3 * arc[a + 1].y + arc[a + 3].y).abs() > ONE_PIXEL / 2
461 || (arc[a].x - 3 * arc[a + 2].x + 2 * arc[a + 3].x).abs() > ONE_PIXEL / 2
462 || (arc[a].y - 3 * arc[a + 2].y + 2 * arc[a + 3].y).abs() > ONE_PIXEL / 2
463 {
464 let buf = &mut arc[a..];
465 if buf.len() >= 7 {
469 split_cubic(buf);
470 a += 3;
471 continue;
472 } else {
473 self.line_to(to);
474 return;
475 }
476 }
477 let p = arc[a];
478 self.line_to(p);
479 if a == 0 {
480 return;
481 }
482 a -= 3;
483 }
484 }
485}
486
487impl<S: RasterStorage> PathBuilder for Rasterizer<'_, S> {
488 fn current_point(&self) -> Point {
489 self.current + self.shift
490 }
491
492 #[inline(always)]
493 fn move_to(&mut self, to: impl Into<Point>) -> &mut Self {
494 if !self.closed {
495 self.line_to(self.start);
496 }
497 let to = to.into();
498 let p = FixedPoint::from_point(to + self.shift);
499 self.move_to(p);
500 self.closed = false;
501 self.start = p;
502 self.current = to;
503 self
504 }
505
506 #[inline(always)]
507 fn line_to(&mut self, to: impl Into<Point>) -> &mut Self {
508 let to = to.into();
509 self.current = to;
510 self.closed = false;
511 self.line_to(FixedPoint::from_point(to + self.shift));
512 self
513 }
514
515 #[inline(always)]
516 fn quad_to(&mut self, control: impl Into<Point>, to: impl Into<Point>) -> &mut Self {
517 let to = to.into();
518 self.current = to;
519 self.closed = false;
520 self.quad_to(
521 FixedPoint::from_point(control.into() + self.shift),
522 FixedPoint::from_point(to + self.shift),
523 );
524 self
525 }
526
527 #[inline(always)]
528 fn curve_to(
529 &mut self,
530 control1: impl Into<Point>,
531 control2: impl Into<Point>,
532 to: impl Into<Point>,
533 ) -> &mut Self {
534 let to = to.into();
535 self.current = to;
536 self.closed = false;
537 self.curve_to(
538 FixedPoint::from_point(control1.into() + self.shift),
539 FixedPoint::from_point(control2.into() + self.shift),
540 FixedPoint::from_point(to + self.shift),
541 );
542 self
543 }
544
545 #[inline(always)]
546 fn close(&mut self) -> &mut Self {
547 self.line_to(self.start);
548 self.closed = true;
549 self
550 }
551}
552
553#[derive(Copy, Clone, Default)]
554pub struct Cell {
555 x: i32,
556 cover: i32,
557 area: i32,
558 next: i32,
559}
560
561pub trait RasterStorage {
562 fn reset(&mut self, min: FixedPoint, max: FixedPoint);
563 fn cells(&self) -> &[Cell];
564 fn indices(&self) -> &[i32];
565 fn set(&mut self, x: i32, y: i32, area: i32, cover: i32);
566}
567
568#[derive(Default)]
569pub struct HeapStorage {
570 min: FixedPoint,
571 max: FixedPoint,
572 cells: Vec<Cell>,
573 indices: Vec<i32>,
574}
575
576impl RasterStorage for HeapStorage {
577 fn reset(&mut self, min: FixedPoint, max: FixedPoint) {
578 self.min = min;
579 self.max = max;
580 self.cells.clear();
581 self.indices.clear();
582 self.indices.resize((max.y - min.y) as usize, -1);
583 }
584
585 fn cells(&self) -> &[Cell] {
586 &self.cells
587 }
588
589 fn indices(&self) -> &[i32] {
590 &self.indices
591 }
592
593 #[inline(always)]
594 #[allow(clippy::comparison_chain)]
595 fn set(&mut self, x: i32, y: i32, area: i32, cover: i32) {
596 let yindex = (y - self.min.y) as usize;
597 let mut cell_index = self.indices[yindex];
598 let mut last_index = -1;
599 while cell_index != -1 {
600 let cell = &mut self.cells[cell_index as usize];
601 if cell.x > x {
602 break;
603 } else if cell.x == x {
604 cell.area = cell.area.wrapping_add(area);
605 cell.cover = cell.cover.wrapping_add(cover);
606 return;
607 }
608 last_index = cell_index;
609 cell_index = cell.next;
610 }
611 let new_index = self.cells.len();
612 let cell = Cell {
613 x,
614 area,
615 cover,
616 next: cell_index,
617 };
618 if last_index != -1 {
619 self.cells[last_index as usize].next = new_index as i32;
620 } else {
621 self.indices[yindex] = new_index as i32;
622 }
623 self.cells.push(cell);
624 }
625}
626
627const MAX_CELLS: usize = 1024;
628const MAX_BAND: usize = 512;
629
630pub struct AdaptiveStorage {
631 min: FixedPoint,
632 max: FixedPoint,
633 height: usize,
634 cell_count: usize,
635 cells: [Cell; MAX_CELLS],
636 heap_cells: Vec<Cell>,
637 indices: [i32; MAX_BAND],
638 heap_indices: Vec<i32>,
639}
640
641impl AdaptiveStorage {
642 #[allow(clippy::uninit_assumed_init, invalid_value)]
643 pub fn new() -> Self {
644 Self {
645 min: FixedPoint::default(),
646 max: FixedPoint::default(),
647 height: 0,
648 cell_count: 0,
649 cells: [Default::default(); MAX_CELLS],
650 heap_cells: Vec::new(),
651 indices: [Default::default(); MAX_BAND],
652 heap_indices: Vec::new(),
653 }
654 }
655}
656
657impl RasterStorage for AdaptiveStorage {
658 fn reset(&mut self, min: FixedPoint, max: FixedPoint) {
659 self.min = min;
660 self.max = max;
661 self.height = (max.y - min.y) as usize;
662 self.cell_count = 0;
663 self.heap_cells.clear();
664 self.heap_indices.clear();
665 if self.height > MAX_BAND {
666 self.heap_indices.resize((max.y - min.y) as usize, -1);
667 } else {
668 for i in 0..self.height {
669 self.indices[i] = -1;
670 }
671 }
672 }
673
674 fn cells(&self) -> &[Cell] {
675 if self.cell_count > MAX_CELLS {
676 &self.heap_cells
677 } else {
678 &self.cells
679 }
680 }
681
682 fn indices(&self) -> &[i32] {
683 if self.height > MAX_BAND {
684 &self.heap_indices
685 } else {
686 &self.indices[..self.height]
687 }
688 }
689
690 #[inline(always)]
691 #[allow(clippy::comparison_chain)]
692 fn set(&mut self, x: i32, y: i32, area: i32, cover: i32) {
693 let yindex = (y - self.min.y) as usize;
694 let indices = if self.height > MAX_BAND {
695 &mut self.heap_indices[..]
696 } else {
697 &mut self.indices[..]
698 };
699 let cells = if !self.heap_cells.is_empty() {
700 &mut self.heap_cells[..]
701 } else {
702 &mut self.cells[..]
703 };
704 let mut cell_index = indices[yindex];
705 let mut last_index = -1;
706 while cell_index != -1 {
707 let cell = &mut cells[cell_index as usize];
708 if cell.x > x {
709 break;
710 } else if cell.x == x {
711 cell.area = cell.area.wrapping_add(area);
712 cell.cover = cell.cover.wrapping_add(cover);
713 return;
714 }
715 last_index = cell_index;
716 cell_index = cell.next;
717 }
718 let new_index = self.cell_count;
719 self.cell_count += 1;
720 let cell = Cell {
721 x,
722 area,
723 cover,
724 next: cell_index,
725 };
726 if last_index != -1 {
727 cells[last_index as usize].next = new_index as i32;
728 } else {
729 indices[yindex] = new_index as i32;
730 }
731 if new_index < MAX_CELLS {
732 cells[new_index] = cell;
733 } else {
734 if self.heap_cells.is_empty() {
735 self.heap_cells.extend_from_slice(&self.cells);
736 }
737 self.heap_cells.push(cell);
738 }
739 }
740}
741
742const _MAX_DIM: u32 = i16::MAX as u32;
743
744fn split_quad(base: &mut [FixedPoint]) {
745 let mut a;
746 let mut b;
747 base[4].x = base[2].x;
748 a = base[0].x + base[1].x;
749 b = base[1].x + base[2].x;
750 base[3].x = b >> 1;
751 base[2].x = (a + b) >> 2;
752 base[1].x = a >> 1;
753 base[4].y = base[2].y;
754 a = base[0].y + base[1].y;
755 b = base[1].y + base[2].y;
756 base[3].y = b >> 1;
757 base[2].y = (a + b) >> 2;
758 base[1].y = a >> 1;
759}
760
761fn split_cubic(base: &mut [FixedPoint]) {
762 let mut a;
763 let mut b;
764 let mut c;
765 base[6].x = base[3].x;
766 a = base[0].x + base[1].x;
767 b = base[1].x + base[2].x;
768 c = base[2].x + base[3].x;
769 base[5].x = c >> 1;
770 c += b;
771 base[4].x = c >> 2;
772 base[1].x = a >> 1;
773 a += b;
774 base[2].x = a >> 2;
775 base[3].x = (a + c) >> 3;
776 base[6].y = base[3].y;
777 a = base[0].y + base[1].y;
778 b = base[1].y + base[2].y;
779 c = base[2].y + base[3].y;
780 base[5].y = c >> 1;
781 c += b;
782 base[4].y = c >> 2;
783 base[1].y = a >> 1;
784 a += b;
785 base[2].y = a >> 2;
786 base[3].y = (a + c) >> 3;
787}
788
789#[derive(Copy, Clone, Default)]
790pub struct FixedPoint {
791 pub x: i32,
792 pub y: i32,
793}
794
795impl fmt::Debug for FixedPoint {
796 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
797 write!(f, "({}, {})", self.x, self.y)
798 }
799}
800
801impl FixedPoint {
802 pub fn new(x: i32, y: i32) -> Self {
803 Self { x, y }
804 }
805
806 #[inline(always)]
807 pub fn from_point(p: Point) -> Self {
808 Self {
809 x: to_fixed(p.x),
810 y: to_fixed(p.y),
811 }
812 }
813}
814
815#[inline(always)]
816fn to_fixed(v: f32) -> i32 {
817 unsafe { (v * 256.).to_int_unchecked() }
818}
819
820const PIXEL_BITS: i32 = 8;
821const ONE_PIXEL: i32 = 1 << PIXEL_BITS;
822
823#[inline(always)]
824fn trunc(x: i32) -> i32 {
825 x >> PIXEL_BITS
826}
827
828#[inline(always)]
829fn fract(x: i32) -> i32 {
830 x & (ONE_PIXEL - 1)
831}