1use alloc::boxed::Box;
27use alloc::vec;
28use alloc::vec::Vec;
29
30use super::path::Path;
31use super::raster::Raster;
32use super::{div255, ERR_FAIL};
33use rt::fx::{cvtt, maxss, minss};
34use simd::{Simd, Sse2};
35
36pub const TM_TILE: usize = 64;
37const TM_SHIFT: u32 = 6;
38const TB: usize = 4096; pub const TM_MAX_SIDE: u32 = 65535;
40pub const TM_REPLACE: u32 = 0; pub const TM_ADD: u32 = 1; pub const TM_SUB: u32 = 2; pub const TM_INTERSECT: u32 = 3; pub const TM_XOR: u32 = 4; pub const TM_OP_COUNT: u32 = 5;
46pub const TM_TRACE_LEVEL: u8 = 128;
47const CHUNK_TILES: u32 = 64; #[derive(Clone, Copy, PartialEq, Eq)]
50enum Slot {
51 Empty,
52 Full,
53 Tile(u32),
54}
55
56pub enum Span<'a> {
58 Empty,
59 Full,
60 Bytes(&'a [u8]),
61}
62
63#[derive(Clone, Copy)]
65pub enum Block<'a> {
66 Empty,
67 Full,
68 Data(&'a [u8], usize), }
70
71#[derive(Clone, Copy, PartialEq, Eq)]
73enum Bo {
74 Max,
75 Sub,
76 Mul,
77 AbsDiff,
78 Inv,
79}
80
81pub struct TMask {
82 pub w: u32,
83 pub h: u32,
84 tw: u32,
85 th: u32,
86 slots: Vec<Slot>,
87 pool: Vec<Box<[u8; TB]>>,
88 free: Vec<u32>,
89 ntiles: u32,
90}
91
92fn bo_byte(op: Bo, d: u8, s: u8) -> u8 {
93 match op {
94 Bo::Max => d.max(s),
95 Bo::Sub => div255(d as u32 * (255 - s as u32)) as u8,
96 Bo::Mul => div255(d as u32 * s as u32) as u8,
97 Bo::AbsDiff => d.abs_diff(s),
98 Bo::Inv => 255 - d,
99 }
100}
101
102fn blk_class(src: &[u8], stride: usize, vw: usize, vh: usize) -> u32 {
104 let (mut any, mut all) = (false, true);
105 for r in 0..vh {
106 for &b in &src[r * stride..r * stride + vw] {
107 any |= b != 0;
108 all &= b == 255;
109 }
110 }
111 if !any {
112 0
113 } else if all {
114 1
115 } else {
116 2
117 }
118}
119
120#[inline(always)]
122fn rows_op(tile: &mut [u8; TB], src: &[u8], stride: usize, f: impl Fn(u8, u8) -> u8) {
123 for (r, row) in tile.as_chunks_mut::<64>().0.iter_mut().enumerate() {
124 let s: &[u8; 64] = src[r * stride..r * stride + 64].try_into().expect("64 bytes");
125 for (d, &v) in row.iter_mut().zip(s) {
126 *d = f(*d, v);
127 }
128 }
129}
130
131#[inline]
134fn rowbits_top(row: &[u8; 64]) -> u64 {
135 let x = Sse2;
136 let mut bits = 0u64;
137 for k in 0..4 {
138 bits |= (x.movemask8(x.load(&row[k * 16..k * 16 + 16])) as u64) << (16 * k);
139 }
140 bits
141}
142
143#[inline]
145fn rowbits_nz(row: &[u8; 64]) -> u64 {
146 let x = Sse2;
147 let mut bits = 0u64;
148 for k in 0..4 {
149 bits |= (x.movemask8(x.cmpeq8(x.load(&row[k * 16..k * 16 + 16]), x.zero())) as u64) << (16 * k);
150 }
151 !bits
152}
153
154fn vmask64(vw: u32) -> u64 {
155 if vw >= 64 { u64::MAX } else { (1u64 << vw) - 1 }
156}
157
158fn f2i_clamp(x: f32) -> i32 {
160 cvtt(minss(maxss(x, -1.0), 70000.0))
161}
162
163impl TMask {
164 pub fn new(w: u32, h: u32) -> Option<TMask> {
166 if !(1..=TM_MAX_SIDE).contains(&w) || !(1..=TM_MAX_SIDE).contains(&h) {
167 return None;
168 }
169 let tw = (w + 63) >> TM_SHIFT;
170 let th = (h + 63) >> TM_SHIFT;
171 Some(TMask { w, h, tw, th, slots: vec![Slot::Empty; (tw * th) as usize], pool: Vec::new(), free: Vec::new(), ntiles: 0 })
172 }
173
174 pub fn tiles_x(&self) -> u32 {
175 self.tw
176 }
177
178 pub fn tiles_y(&self) -> u32 {
179 self.th
180 }
181
182 fn si(&self, tx: u32, ty: u32) -> usize {
185 (ty * self.tw + tx) as usize
186 }
187
188 fn tile_dims(&self, tx: u32, ty: u32) -> (usize, usize) {
190 let vw = (self.w - (tx << TM_SHIFT)).min(64);
191 let vh = (self.h - (ty << TM_SHIFT)).min(64);
192 (vw as usize, vh as usize)
193 }
194
195 fn tile_alloc(&mut self) -> u32 {
196 self.ntiles += 1;
197 if let Some(t) = self.free.pop() {
198 return t;
199 }
200 self.pool.push(Box::new([0u8; TB]));
201 self.pool.len() as u32 - 1
202 }
203
204 fn slot_put(&mut self, i: usize, v: Slot) {
206 if let Slot::Tile(t) = self.slots[i] {
207 self.free.push(t);
208 self.ntiles -= 1;
209 }
210 self.slots[i] = v;
211 }
212
213 fn slot_tile(&mut self, i: usize, fill: bool) -> u32 {
215 match self.slots[i] {
216 Slot::Tile(t) => t,
217 s => {
218 let t = self.tile_alloc();
219 self.slots[i] = Slot::Tile(t);
220 if fill {
221 self.pool[t as usize].fill(if s == Slot::Full { 255 } else { 0 });
222 }
223 t
224 }
225 }
226 }
227
228 fn slot_norm(&mut self, i: usize, vw: usize, vh: usize) {
230 if let Slot::Tile(t) = self.slots[i] {
231 match blk_class(&self.pool[t as usize][..], 64, vw, vh) {
232 0 => self.slot_put(i, Slot::Empty),
233 1 => self.slot_put(i, Slot::Full),
234 _ => {}
235 }
236 }
237 }
238
239 fn drop_tiles(&mut self) {
240 self.pool.clear();
241 self.free.clear();
242 self.ntiles = 0;
243 }
244
245 fn blk_op(&mut self, t: u32, src: Block, op: Bo) {
246 let tile = &mut self.pool[t as usize];
247 match src {
248 Block::Data(s, stride) => match op {
250 Bo::Max => rows_op(tile, s, stride, |d, s| d.max(s)),
251 Bo::Sub => rows_op(tile, s, stride, |d, s| div255(d as u32 * (255 - s as u32)) as u8),
252 Bo::Mul => rows_op(tile, s, stride, |d, s| div255(d as u32 * s as u32) as u8),
253 Bo::AbsDiff => rows_op(tile, s, stride, |d, s| d.abs_diff(s)),
254 Bo::Inv => rows_op(tile, s, stride, |d, _| 255 - d),
255 },
256 _ => {
257 for b in tile.iter_mut() {
259 *b = bo_byte(op, *b, *b);
260 }
261 }
262 }
263 }
264
265 pub fn clear(&mut self, value: u8) -> i32 {
269 self.drop_tiles();
270 let s = if value == 255 { Slot::Full } else { Slot::Empty };
271 self.slots.iter_mut().for_each(|x| *x = s);
272 if value != 0 && value != 255 {
273 for i in 0..self.slots.len() {
274 let t = self.slot_tile(i, false);
275 self.pool[t as usize].fill(value);
276 }
277 }
278 0
279 }
280
281 pub fn get(&self, x: i32, y: i32) -> u8 {
283 if x as u32 >= self.w || y as u32 >= self.h {
284 return 0;
285 }
286 let (x, y) = (x as u32, y as u32);
287 match self.slots[self.si(x >> TM_SHIFT, y >> TM_SHIFT)] {
288 Slot::Empty => 0,
289 Slot::Full => 255,
290 Slot::Tile(t) => self.pool[t as usize][((y & 63) << TM_SHIFT | (x & 63)) as usize],
291 }
292 }
293
294 pub fn span(&self, x: i32, y: i32, maxn: i32) -> (Span<'_>, i32) {
296 if maxn <= 0 {
297 return (Span::Empty, 0);
298 }
299 if y as u32 >= self.h {
300 return (Span::Empty, maxn); }
302 if x < 0 {
303 return (Span::Empty, (-(x as i64)).min(maxn as i64) as i32);
304 }
305 if x as u32 >= self.w {
306 return (Span::Empty, maxn);
307 }
308 let maxn = maxn.min(self.w as i32 - x);
309 let (xu, yu) = (x as u32, y as u32);
310 let mut i = self.si(xu >> TM_SHIFT, yu >> TM_SHIFT);
311 let s = self.slots[i];
312 let mut left = 64 - (xu & 63) as i32;
313 match s {
314 Slot::Tile(t) => {
315 let o = ((yu & 63) << TM_SHIFT | (xu & 63)) as usize;
316 let n = left.min(maxn);
317 (Span::Bytes(&self.pool[t as usize][o..o + n as usize]), n)
318 }
319 _ => {
320 while left < maxn {
321 i += 1;
322 if self.slots[i] != s {
323 break;
324 }
325 left += 64;
326 }
327 (if s == Slot::Full { Span::Full } else { Span::Empty }, left.min(maxn))
328 }
329 }
330 }
331
332 pub fn row<'a>(&'a self, x: i32, y: i32, n: i32, buf: &'a mut [u8]) -> (&'a [u8], bool) {
334 if n <= 0 {
335 return (&buf[..0], true);
336 }
337 if let (Span::Bytes(b), k) = self.span(x, y, n) {
338 if k == n {
339 return (b, false); }
341 }
342 let (mut x, mut left, mut o) = (x, n, 0usize);
343 while left > 0 {
344 let (sp, k) = self.span(x, y, left);
345 let k = k as usize;
346 match sp {
347 Span::Empty => buf[o..o + k].fill(0),
348 Span::Full => buf[o..o + k].fill(255),
349 Span::Bytes(b) => buf[o..o + k].copy_from_slice(b),
350 }
351 o += k;
352 x += k as i32;
353 left -= k as i32;
354 }
355 (&buf[..n as usize], true)
356 }
357
358 pub fn row_w(&mut self, x: i32, y: i32) -> Option<&mut [u8]> {
360 if x as u32 >= self.w || y as u32 >= self.h {
361 return None;
362 }
363 let (xu, yu) = (x as u32, y as u32);
364 let i = self.si(xu >> TM_SHIFT, yu >> TM_SHIFT);
365 let t = self.slot_tile(i, true);
366 let o = ((yu & 63) << TM_SHIFT | (xu & 63)) as usize;
367 let n = ((64 - (xu & 63)).min(self.w - xu)) as usize;
368 Some(&mut self.pool[t as usize][o..o + n])
369 }
370
371 pub fn tile_w(&mut self, tx: u32, ty: u32) -> Option<&mut [u8]> {
373 if tx >= self.tw || ty >= self.th {
374 return None;
375 }
376 let i = self.si(tx, ty);
377 let t = self.slot_tile(i, true);
378 Some(&mut self.pool[t as usize][..])
379 }
380
381 pub fn tile_set(&mut self, tx: u32, ty: u32, full: bool) {
383 if tx >= self.tw || ty >= self.th {
384 return;
385 }
386 let i = self.si(tx, ty);
387 self.slot_put(i, if full { Slot::Full } else { Slot::Empty });
388 }
389
390 pub fn fill_rect(&mut self, x0: i32, y0: i32, x1: i32, y1: i32, value: u8) -> i32 {
393 let x0 = x0.max(0);
394 let y0 = y0.max(0);
395 let x1 = x1.min(self.w as i32);
396 let y1 = y1.min(self.h as i32);
397 if x1 <= x0 || y1 <= y0 {
398 return 0;
399 }
400 let kind = match value {
401 0 => Some(Slot::Empty),
402 255 => Some(Slot::Full),
403 _ => None,
404 };
405 for ty in (y0 as u32 >> TM_SHIFT)..=((y1 - 1) as u32 >> TM_SHIFT) {
406 for tx in (x0 as u32 >> TM_SHIFT)..=((x1 - 1) as u32 >> TM_SHIFT) {
407 let (vw, vh) = self.tile_dims(tx, ty);
408 let (tx0, ty0) = ((tx << TM_SHIFT) as i32, (ty << TM_SHIFT) as i32);
409 let (tx1, ty1) = (tx0 + vw as i32, ty0 + vh as i32);
410 let (rx0, rx1, ry0, ry1) = (x0.max(tx0), x1.min(tx1), y0.max(ty0), y1.min(ty1));
411 let i = self.si(tx, ty);
412 if let Some(k) = kind {
413 if rx0 == tx0 && rx1 == tx1 && ry0 == ty0 && ry1 == ty1 {
414 self.slot_put(i, k);
415 continue;
416 }
417 if self.slots[i] == k {
418 continue; }
420 }
421 let t = self.slot_tile(i, true) as usize;
422 for y in ry0..ry1 {
423 let o = ((y & 63) << TM_SHIFT) as usize + (rx0 & 63) as usize;
424 self.pool[t][o..o + (rx1 - rx0) as usize].fill(value);
425 }
426 }
427 }
428 0
429 }
430
431 pub fn combine_block(&mut self, tx: u32, ty: u32, src: Block, op: u32) -> i32 {
433 if tx >= self.tw || ty >= self.th {
434 return 0;
435 }
436 let (vw, vh) = self.tile_dims(tx, ty);
437 let i = self.si(tx, ty);
438 let mut src = src;
439 if let Block::Data(b, stride) = src {
440 match blk_class(b, stride, vw, vh) {
441 0 => src = Block::Empty, 1 => src = Block::Full,
443 _ => {}
444 }
445 }
446 let d = self.slots[i];
447 enum Act {
448 Nothing,
449 Set(Slot),
450 Copy,
451 InvCopy,
452 Op(Bo),
453 InvTile,
454 }
455 let act = match op {
456 TM_REPLACE => match src {
457 Block::Empty => Act::Set(Slot::Empty),
458 Block::Full => Act::Set(Slot::Full),
459 _ => Act::Copy,
460 },
461 TM_ADD => match (src, d) {
462 (Block::Empty, _) => Act::Nothing,
463 (Block::Full, _) => Act::Set(Slot::Full),
464 (_, Slot::Empty) => Act::Copy,
465 (_, Slot::Full) => Act::Nothing,
466 _ => Act::Op(Bo::Max),
467 },
468 TM_SUB => match (src, d) {
469 (Block::Empty, _) => Act::Nothing,
470 (Block::Full, _) => Act::Set(Slot::Empty),
471 (_, Slot::Empty) => Act::Nothing,
472 (_, Slot::Full) => Act::InvCopy,
473 _ => Act::Op(Bo::Sub),
474 },
475 TM_INTERSECT => match (src, d) {
476 (Block::Empty, _) => Act::Set(Slot::Empty),
477 (Block::Full, _) => Act::Nothing,
478 (_, Slot::Empty) => Act::Nothing,
479 (_, Slot::Full) => Act::Copy,
480 _ => Act::Op(Bo::Mul),
481 },
482 TM_XOR => match (src, d) {
483 (Block::Empty, _) => Act::Nothing,
484 (Block::Full, Slot::Empty) => Act::Set(Slot::Full),
485 (Block::Full, Slot::Full) => Act::Set(Slot::Empty),
486 (Block::Full, _) => Act::InvTile,
487 (_, Slot::Empty) => Act::Copy,
488 (_, Slot::Full) => Act::InvCopy,
489 _ => Act::Op(Bo::AbsDiff),
490 },
491 _ => return ERR_FAIL,
492 };
493 match act {
494 Act::Nothing => {}
495 Act::Set(s) => self.slot_put(i, s),
496 Act::Copy | Act::InvCopy => {
497 let t = self.slot_tile(i, false) as usize;
498 if let Block::Data(b, stride) = src {
499 let tile = &mut self.pool[t];
500 if matches!(act, Act::InvCopy) {
502 rows_op(tile, b, stride, |_, v| 255 - v);
503 } else {
504 for (r, row) in tile.as_chunks_mut::<64>().0.iter_mut().enumerate() {
505 row.copy_from_slice(&b[r * stride..r * stride + 64]);
506 }
507 }
508 }
509 }
510 Act::InvTile => {
511 if let Slot::Tile(t) = d {
512 self.blk_op(t, Block::Empty, Bo::Inv);
513 }
514 }
515 Act::Op(bo) => {
516 if let Slot::Tile(t) = d {
517 self.blk_op(t, src, bo);
518 self.slot_norm(i, vw, vh);
519 }
520 }
521 }
522 0
523 }
524
525 pub fn combine(&mut self, src: &TMask, op: u32) -> i32 {
527 if self.w != src.w || self.h != src.h {
528 return ERR_FAIL;
529 }
530 for ty in 0..self.th {
531 for tx in 0..self.tw {
532 let b = match src.slots[src.si(tx, ty)] {
533 Slot::Empty => Block::Empty,
534 Slot::Full => Block::Full,
535 Slot::Tile(t) => Block::Data(&src.pool[t as usize][..], 64),
536 };
537 let r = self.combine_block(tx, ty, b, op);
538 if r != 0 {
539 return r;
540 }
541 }
542 }
543 0
544 }
545
546 pub fn combine_self(&mut self, op: u32) -> i32 {
548 let copy = self.clone();
549 self.combine(©, op)
550 }
551
552 pub fn copy(&mut self, src: &TMask) -> i32 {
554 self.combine(src, TM_REPLACE)
555 }
556
557 pub fn invert(&mut self) {
559 for i in 0..self.slots.len() {
560 match self.slots[i] {
561 Slot::Empty => self.slots[i] = Slot::Full,
562 Slot::Full => self.slots[i] = Slot::Empty,
563 Slot::Tile(t) => self.blk_op(t, Block::Empty, Bo::Inv),
564 }
565 }
566 }
567
568 pub fn threshold(&mut self, level: i32) {
570 let level = level.clamp(1, 255) as u8;
571 for ty in 0..self.th {
572 for tx in 0..self.tw {
573 let i = self.si(tx, ty);
574 if let Slot::Tile(t) = self.slots[i] {
575 for b in self.pool[t as usize].iter_mut() {
576 *b = if *b >= level { 255 } else { 0 };
577 }
578 let (vw, vh) = self.tile_dims(tx, ty);
579 self.slot_norm(i, vw, vh);
580 }
581 }
582 }
583 }
584
585 pub fn optimize(&mut self) {
587 for ty in 0..self.th {
588 for tx in 0..self.tw {
589 let (vw, vh) = self.tile_dims(tx, ty);
590 let i = self.si(tx, ty);
591 self.slot_norm(i, vw, vh);
592 }
593 }
594 }
595
596 pub fn count_tiles(&self) -> (u32, u32) {
598 (self.ntiles, self.slots.iter().filter(|s| **s == Slot::Full).count() as u32)
599 }
600
601 pub fn bbox(&self) -> Option<[i32; 4]> {
603 let mut b = [i32::MAX, i32::MAX, -1, -1]; let mut add = |x0: i32, y0: i32, x1: i32, y1: i32| {
605 b[0] = b[0].min(x0);
606 b[1] = b[1].min(y0);
607 b[2] = b[2].max(x1);
608 b[3] = b[3].max(y1);
609 };
610 for ty in 0..self.th {
611 for tx in 0..self.tw {
612 let (vw, vh) = self.tile_dims(tx, ty);
613 let (x0, y0) = ((tx << TM_SHIFT) as i32, (ty << TM_SHIFT) as i32);
614 match self.slots[self.si(tx, ty)] {
615 Slot::Empty => {}
616 Slot::Full => add(x0, y0, x0 + vw as i32 - 1, y0 + vh as i32 - 1),
617 Slot::Tile(t) => {
618 let m = vmask64(vw as u32);
619 for r in 0..vh {
620 let row: &[u8; 64] = self.pool[t as usize][r * 64..r * 64 + 64].try_into().expect("64 bytes");
621 let bits = rowbits_nz(row) & m;
622 if bits != 0 {
623 let (lo, hi) = (bits.trailing_zeros() as i32, 63 - bits.leading_zeros() as i32);
624 add(x0 + lo, y0 + r as i32, x0 + hi, y0 + r as i32);
625 }
626 }
627 }
628 }
629 }
630 }
631 if b[2] < 0 { None } else { Some([b[0], b[1], b[2] + 1, b[3] + 1]) }
632 }
633
634 pub fn load_a8(&mut self, src: &[u8], stride: usize) -> i32 {
636 let mut tmp = vec![0u8; TB];
637 for ty in 0..self.th {
638 for tx in 0..self.tw {
639 let (vw, vh) = self.tile_dims(tx, ty);
640 let o = (ty as usize * 64) * stride + tx as usize * 64;
641 let r = if vw == 64 && vh == 64 {
642 self.combine_block(tx, ty, Block::Data(&src[o..], stride), TM_REPLACE)
643 } else {
644 for row in 0..vh {
646 tmp[row * 64..row * 64 + vw].copy_from_slice(&src[o + row * stride..o + row * stride + vw]);
647 }
648 self.combine_block(tx, ty, Block::Data(&tmp, 64), TM_REPLACE)
649 };
650 if r != 0 {
651 return r;
652 }
653 }
654 }
655 0
656 }
657
658 pub fn store_a8(&self, dst: &mut [u8], stride: usize) {
660 for ty in 0..self.th {
661 for tx in 0..self.tw {
662 let (vw, vh) = self.tile_dims(tx, ty);
663 let o = (ty as usize * 64) * stride + tx as usize * 64;
664 let s = self.slots[self.si(tx, ty)];
665 for row in 0..vh {
666 let d = &mut dst[o + row * stride..o + row * stride + vw];
667 match s {
668 Slot::Empty => d.fill(0),
669 Slot::Full => d.fill(255),
670 Slot::Tile(t) => d.copy_from_slice(&self.pool[t as usize][row * 64..row * 64 + vw]),
671 }
672 }
673 }
674 }
675 }
676
677 pub fn raster_path(&mut self, path: &Path, ras: &mut Raster, rule: u32, op: u32) -> i32 {
680 if op >= TM_OP_COUNT {
681 return ERR_FAIL;
682 }
683 path.fill_lines(ras);
684 let mut op = op;
685 if op == TM_REPLACE {
686 self.clear(0);
687 op = TM_ADD;
688 }
689 let range = if ras.has_lines() {
690 let lb = ras.lbox();
691 let tx0 = (f2i_clamp(lb[0]).max(0) as u32) >> TM_SHIFT;
692 let ty0 = (f2i_clamp(lb[1]).max(0) as u32) >> TM_SHIFT;
693 let ex = f2i_clamp(lb[2]) + 2 + 63; let ey = f2i_clamp(lb[3]) + 2 + 63;
695 if ex < 0 || ey < 0 {
696 None
697 } else {
698 let tx1 = ((ex as u32) >> TM_SHIFT).min(self.tw);
699 let ty1 = ((ey as u32) >> TM_SHIFT).min(self.th);
700 if tx1 <= tx0 || ty1 <= ty0 { None } else { Some((tx0, tx1, ty0, ty1)) }
701 }
702 } else {
703 None
704 };
705 let Some((tx0, tx1, ty0, ty1)) = range else {
706 if op == TM_INTERSECT {
708 self.clear(0);
709 }
710 return 0;
711 };
712 if op == TM_INTERSECT {
713 for ty in 0..self.th {
714 for tx in 0..self.tw {
715 if ty < ty0 || ty >= ty1 || tx < tx0 || tx >= tx1 {
716 self.tile_set(tx, ty, false);
717 }
718 }
719 }
720 }
721 let chunk = (tx1 - tx0).min(CHUNK_TILES);
722 let rowb = (chunk * 64) as usize;
723 let mut buf = vec![0u8; rowb * 64];
724 for ty in ty0..ty1 {
725 let mut cx = tx0;
726 while cx < tx1 {
727 let cols = (tx1 - cx).min(chunk);
728 let (bx, by) = ((cx * 64) as i32, (ty * 64) as i32);
729 let clip = [bx, by, (bx + (cols * 64) as i32).min(self.w as i32), (by + 64).min(self.h as i32)];
730 let mut rows = [(0usize, 0usize); 64]; let (mut lo, mut hi) = (usize::MAX, 0usize);
737 ras.fill_rows(clip, rule, &mut |y, x, cov| {
738 let (r, o) = ((y - by) as usize, (x - bx) as usize);
739 buf[r * rowb + o..r * rowb + o + cov.len()].copy_from_slice(cov);
740 rows[r] = (o, cov.len());
741 lo = lo.min(o);
742 hi = hi.max(o + cov.len());
743 });
744 for col in 0..cols {
745 let c0 = (col * 64) as usize;
746 let src = if c0 + 64 <= lo || c0 >= hi { Block::Empty } else { Block::Data(&buf[c0..], rowb) };
747 let r = self.combine_block(cx + col, ty, src, op);
748 if r != 0 {
749 return r;
750 }
751 }
752 for (r, &(o, n)) in rows.iter().enumerate() {
753 buf[r * rowb + o..r * rowb + o + n].fill(0);
754 }
755 cx += chunk;
756 }
757 }
758 0
759 }
760
761 pub fn raster_polygon(&mut self, path: &mut Path, ras: &mut Raster, pts: &[(f32, f32)], rule: u32, op: u32) -> i32 {
763 path.reset();
764 if let Some(&(x, y)) = pts.first() {
765 path.move_f(x, y);
766 for &(x, y) in &pts[1..] {
767 path.line_f(x, y);
768 }
769 }
770 self.raster_path(path, ras, rule, op)
771 }
772
773 fn tr_rowbits(&self, tx: u32, y: i32) -> u64 {
777 if y as u32 >= self.h {
778 return 0;
779 }
780 let m = vmask64((self.w - (tx << TM_SHIFT)).min(64));
781 match self.slots[self.si(tx, y as u32 >> TM_SHIFT)] {
782 Slot::Empty => 0,
783 Slot::Full => m,
784 Slot::Tile(t) => {
785 let o = ((y as u32 & 63) << TM_SHIFT) as usize;
786 rowbits_top(self.pool[t as usize][o..o + 64].try_into().expect("64 bytes")) & m
788 }
789 }
790 }
791
792 pub fn trace(&self, cb: &mut dyn FnMut(&[(i32, i32)]) -> i32) -> i32 {
796 let mut tr = Tracer { tm: self, vis: vec![None; (self.th + 1) as usize], pts: Vec::new(), cb };
797 let tw = self.tw as usize;
798 for ty in 0..self.th {
799 let row = &self.slots[ty as usize * tw..(ty as usize + 1) * tw];
801 let above_row = if ty == 0 { &[][..] } else { &self.slots[(ty as usize - 1) * tw..ty as usize * tw] };
802 for tx in 0..self.tw {
803 let s = row[tx as usize];
804 let above = above_row.get(tx as usize).copied().unwrap_or(Slot::Empty);
805 let y0 = (ty << TM_SHIFT) as i32;
806 let last = if (y0 + 64) < self.h as i32 { y0 + 63 } else { self.h as i32 };
807 let r = if let Slot::Tile(_) = s {
808 let mut r = 0;
809 for y in y0..=last {
810 r = tr.scan(tx, y);
811 if r != 0 {
812 break;
813 }
814 }
815 r
816 } else {
817 let mut r = 0;
819 if s != above {
820 r = tr.scan(tx, y0);
821 }
822 if r == 0 && last == self.h as i32 && s == Slot::Full {
823 r = tr.scan(tx, last);
824 }
825 r
826 };
827 if r != 0 {
828 return r;
829 }
830 }
831 }
832 0
833 }
834}
835
836impl Clone for TMask {
837 fn clone(&self) -> TMask {
838 let mut m = TMask::new(self.w, self.h).expect("valid size");
839 m.copy(self);
840 m
841 }
842}
843
844const ARX: [i32; 4] = [0, -1, -1, 0];
847const ARY: [i32; 4] = [0, 0, -1, -1];
848const ALX: [i32; 4] = [0, 0, -1, -1];
849const ALY: [i32; 4] = [-1, 0, 0, -1];
850
851struct Tracer<'a> {
852 tm: &'a TMask,
853 vis: Vec<Option<Box<[Option<Box<[u64; 64]>>]>>>,
857 pts: Vec<(i32, i32)>,
858 cb: &'a mut dyn FnMut(&[(i32, i32)]) -> i32,
859}
860
861impl Tracer<'_> {
862 fn word(&mut self, tx: u32, y: i32) -> &mut u64 {
863 let tw = self.tm.tw as usize;
864 let cols = self.vis[(y as u32 >> TM_SHIFT) as usize].get_or_insert_with(|| vec![None; tw].into_boxed_slice());
865 let blk = cols[tx as usize].get_or_insert_with(|| Box::new([0u64; 64]));
866 &mut blk[(y & 63) as usize]
867 }
868
869 fn mark(&mut self, x: i32, y: i32) {
870 *self.word(x as u32 >> TM_SHIFT, y) |= 1u64 << (x & 63);
871 }
872
873 fn follow(&mut self, x: i32, y: i32, below: bool) -> i32 {
876 let (mut p0x, p0y, d0) = (x, y, if below { 0 } else { 2 });
877 if !below {
878 p0x += 1;
879 }
880 self.pts.clear();
881 self.pts.push((p0x, p0y));
882 let (mut px, mut py, mut d) = (p0x, p0y, d0);
883 loop {
884 match d {
885 0 => {
886 self.mark(px, py);
887 px += 1;
888 }
889 1 => py += 1,
890 2 => {
891 self.mark(px - 1, py);
892 px -= 1;
893 }
894 _ => py -= 1,
895 }
896 let ar = self.tm.get(px + ARX[d], py + ARY[d]);
897 let al = self.tm.get(px + ALX[d], py + ALY[d]);
898 let nd = if ar < TM_TRACE_LEVEL {
899 (d + 1) & 3 } else if al < TM_TRACE_LEVEL {
901 d } else {
903 (d + 3) & 3 };
905 if px == p0x && py == p0y && nd == d0 {
906 let pts = if d == d0 { &self.pts[1..] } else { &self.pts[..] };
908 return (self.cb)(pts);
909 }
910 if nd != d {
911 self.pts.push((px, py));
912 }
913 d = nd;
914 }
915 }
916
917 fn scan(&mut self, tx: u32, y: i32) -> i32 {
919 let above = self.tm.tr_rowbits(tx, y - 1);
920 let below = self.tm.tr_rowbits(tx, y);
921 let edges = above ^ below;
922 if edges == 0 {
923 return 0;
924 }
925 loop {
926 let open = !*self.word(tx, y) & edges;
927 if open == 0 {
928 return 0;
929 }
930 let bit = open.trailing_zeros() as i32;
931 let r = self.follow((tx << TM_SHIFT) as i32 + bit, y, below >> bit & 1 != 0);
932 if r != 0 {
933 return r;
934 }
935 }
936 }
937}