1use crate::basics::{iround, Rect, POLY_SUBPIXEL_SCALE};
11use crate::clip_liang_barsky::{clipping_flags, clipping_flags_y};
12use crate::rasterizer_cells_aa::RasterizerCellsAa;
13
14#[inline]
20fn upscale(v: f64) -> i32 {
21 iround(v * POLY_SUBPIXEL_SCALE as f64)
22}
23
24#[inline]
26fn xi(v: i32) -> i32 {
27 v
28}
29
30#[inline]
32fn yi(v: i32) -> i32 {
33 v
34}
35
36#[inline]
38fn mul_div(a: i32, b: i32, c: i32) -> i32 {
39 iround(a as f64 * b as f64 / c as f64)
40}
41
42pub struct RasterizerSlClipInt {
51 clip_box: Rect<i32>,
52 x1: i32,
53 y1: i32,
54 f1: u32,
55 clipping: bool,
56}
57
58impl RasterizerSlClipInt {
59 pub fn new() -> Self {
60 Self {
61 clip_box: Rect::new(0, 0, 0, 0),
62 x1: 0,
63 y1: 0,
64 f1: 0,
65 clipping: false,
66 }
67 }
68
69 pub fn reset_clipping(&mut self) {
71 self.clipping = false;
72 }
73
74 pub fn clip_box(&mut self, x1: i32, y1: i32, x2: i32, y2: i32) {
76 self.clip_box = Rect::new(x1, y1, x2, y2);
77 self.clip_box.normalize();
78 self.clipping = true;
79 }
80
81 pub fn move_to(&mut self, x1: i32, y1: i32) {
83 self.x1 = x1;
84 self.y1 = y1;
85 if self.clipping {
86 self.f1 = clipping_flags(x1, y1, &self.clip_box);
87 }
88 }
89
90 pub fn move_to_d(&mut self, x: f64, y: f64) {
92 self.move_to(upscale(x), upscale(y));
93 }
94
95 pub fn line_to(&mut self, ras: &mut RasterizerCellsAa, x2: i32, y2: i32) {
99 if self.clipping {
100 let f2 = clipping_flags(x2, y2, &self.clip_box);
101
102 if (self.f1 & 10) == (f2 & 10) && (self.f1 & 10) != 0 {
104 self.x1 = x2;
105 self.y1 = y2;
106 self.f1 = f2;
107 return;
108 }
109
110 let x1 = self.x1;
111 let y1 = self.y1;
112 let f1 = self.f1;
113
114 match ((f1 & 5) << 1) | (f2 & 5) {
115 0 => {
116 self.line_clip_y(ras, x1, y1, x2, y2, f1, f2);
118 }
119 1 => {
120 let y3 = y1 + mul_div(self.clip_box.x2 - x1, y2 - y1, x2 - x1);
122 let f3 = clipping_flags_y(y3, &self.clip_box);
123 self.line_clip_y(ras, x1, y1, self.clip_box.x2, y3, f1, f3);
124 self.line_clip_y(ras, self.clip_box.x2, y3, self.clip_box.x2, y2, f3, f2);
125 }
126 2 => {
127 let y3 = y1 + mul_div(self.clip_box.x2 - x1, y2 - y1, x2 - x1);
129 let f3 = clipping_flags_y(y3, &self.clip_box);
130 self.line_clip_y(ras, self.clip_box.x2, y1, self.clip_box.x2, y3, f1, f3);
131 self.line_clip_y(ras, self.clip_box.x2, y3, x2, y2, f3, f2);
132 }
133 3 => {
134 self.line_clip_y(ras, self.clip_box.x2, y1, self.clip_box.x2, y2, f1, f2);
136 }
137 4 => {
138 let y3 = y1 + mul_div(self.clip_box.x1 - x1, y2 - y1, x2 - x1);
140 let f3 = clipping_flags_y(y3, &self.clip_box);
141 self.line_clip_y(ras, x1, y1, self.clip_box.x1, y3, f1, f3);
142 self.line_clip_y(ras, self.clip_box.x1, y3, self.clip_box.x1, y2, f3, f2);
143 }
144 6 => {
145 let y3 = y1 + mul_div(self.clip_box.x2 - x1, y2 - y1, x2 - x1);
147 let y4 = y1 + mul_div(self.clip_box.x1 - x1, y2 - y1, x2 - x1);
148 let f3 = clipping_flags_y(y3, &self.clip_box);
149 let f4 = clipping_flags_y(y4, &self.clip_box);
150 self.line_clip_y(ras, self.clip_box.x2, y1, self.clip_box.x2, y3, f1, f3);
151 self.line_clip_y(ras, self.clip_box.x2, y3, self.clip_box.x1, y4, f3, f4);
152 self.line_clip_y(ras, self.clip_box.x1, y4, self.clip_box.x1, y2, f4, f2);
153 }
154 8 => {
155 let y3 = y1 + mul_div(self.clip_box.x1 - x1, y2 - y1, x2 - x1);
157 let f3 = clipping_flags_y(y3, &self.clip_box);
158 self.line_clip_y(ras, self.clip_box.x1, y1, self.clip_box.x1, y3, f1, f3);
159 self.line_clip_y(ras, self.clip_box.x1, y3, x2, y2, f3, f2);
160 }
161 9 => {
162 let y3 = y1 + mul_div(self.clip_box.x1 - x1, y2 - y1, x2 - x1);
164 let y4 = y1 + mul_div(self.clip_box.x2 - x1, y2 - y1, x2 - x1);
165 let f3 = clipping_flags_y(y3, &self.clip_box);
166 let f4 = clipping_flags_y(y4, &self.clip_box);
167 self.line_clip_y(ras, self.clip_box.x1, y1, self.clip_box.x1, y3, f1, f3);
168 self.line_clip_y(ras, self.clip_box.x1, y3, self.clip_box.x2, y4, f3, f4);
169 self.line_clip_y(ras, self.clip_box.x2, y4, self.clip_box.x2, y2, f4, f2);
170 }
171 12 => {
172 self.line_clip_y(ras, self.clip_box.x1, y1, self.clip_box.x1, y2, f1, f2);
174 }
175 _ => {
176 }
178 }
179 self.f1 = f2;
180 } else {
181 ras.line(xi(self.x1), yi(self.y1), xi(x2), yi(y2));
182 }
183 self.x1 = x2;
184 self.y1 = y2;
185 }
186
187 pub fn line_to_d(&mut self, ras: &mut RasterizerCellsAa, x: f64, y: f64) {
189 self.line_to(ras, upscale(x), upscale(y));
190 }
191
192 #[allow(clippy::too_many_arguments)]
194 fn line_clip_y(
195 &self,
196 ras: &mut RasterizerCellsAa,
197 x1: i32,
198 y1: i32,
199 x2: i32,
200 y2: i32,
201 f1: u32,
202 f2: u32,
203 ) {
204 let f1 = f1 & 10;
205 let f2 = f2 & 10;
206
207 if (f1 | f2) == 0 {
208 ras.line(xi(x1), yi(y1), xi(x2), yi(y2));
210 } else if f1 != f2 {
211 let mut tx1 = x1;
213 let mut ty1 = y1;
214 let mut tx2 = x2;
215 let mut ty2 = y2;
216
217 if f1 & 8 != 0 {
218 tx1 = x1 + mul_div(self.clip_box.y1 - y1, x2 - x1, y2 - y1);
220 ty1 = self.clip_box.y1;
221 }
222
223 if f1 & 2 != 0 {
224 tx1 = x1 + mul_div(self.clip_box.y2 - y1, x2 - x1, y2 - y1);
226 ty1 = self.clip_box.y2;
227 }
228
229 if f2 & 8 != 0 {
230 tx2 = x1 + mul_div(self.clip_box.y1 - y1, x2 - x1, y2 - y1);
232 ty2 = self.clip_box.y1;
233 }
234
235 if f2 & 2 != 0 {
236 tx2 = x1 + mul_div(self.clip_box.y2 - y1, x2 - x1, y2 - y1);
238 ty2 = self.clip_box.y2;
239 }
240
241 ras.line(xi(tx1), yi(ty1), xi(tx2), yi(ty2));
242 }
243 }
245}
246
247impl Default for RasterizerSlClipInt {
248 fn default() -> Self {
249 Self::new()
250 }
251}
252
253pub struct RasterizerSlNoClip {
263 x1: i32,
264 y1: i32,
265}
266
267impl RasterizerSlNoClip {
268 pub fn new() -> Self {
269 Self { x1: 0, y1: 0 }
270 }
271
272 pub fn reset_clipping(&mut self) {}
273
274 pub fn clip_box(&mut self, _x1: i32, _y1: i32, _x2: i32, _y2: i32) {}
275
276 pub fn move_to(&mut self, x1: i32, y1: i32) {
277 self.x1 = x1;
278 self.y1 = y1;
279 }
280
281 pub fn move_to_d(&mut self, x: f64, y: f64) {
282 self.move_to(upscale(x), upscale(y));
283 }
284
285 pub fn line_to(&mut self, ras: &mut RasterizerCellsAa, x2: i32, y2: i32) {
286 ras.line(self.x1, self.y1, x2, y2);
287 self.x1 = x2;
288 self.y1 = y2;
289 }
290
291 pub fn line_to_d(&mut self, ras: &mut RasterizerCellsAa, x: f64, y: f64) {
292 self.line_to(ras, upscale(x), upscale(y));
293 }
294}
295
296impl Default for RasterizerSlNoClip {
297 fn default() -> Self {
298 Self::new()
299 }
300}
301
302pub fn poly_coord(v: f64) -> i32 {
309 upscale(v)
310}
311
312#[cfg(test)]
317mod tests {
318 use super::*;
319 use crate::basics::POLY_SUBPIXEL_SCALE;
320
321 #[test]
322 fn test_upscale() {
323 assert_eq!(upscale(0.0), 0);
324 assert_eq!(upscale(1.0), POLY_SUBPIXEL_SCALE as i32);
325 assert_eq!(upscale(10.5), iround(10.5 * POLY_SUBPIXEL_SCALE as f64));
326 assert_eq!(upscale(-1.0), -(POLY_SUBPIXEL_SCALE as i32));
327 }
328
329 #[test]
330 fn test_mul_div() {
331 assert_eq!(mul_div(10, 20, 5), 40);
332 assert_eq!(mul_div(0, 100, 1), 0);
333 assert_eq!(mul_div(7, 3, 2), 11); }
335
336 #[test]
341 fn test_clip_int_new() {
342 let clip = RasterizerSlClipInt::new();
343 assert!(!clip.clipping);
344 }
345
346 #[test]
347 fn test_clip_int_no_clip_passthrough() {
348 let mut clip = RasterizerSlClipInt::new();
349 let mut ras = RasterizerCellsAa::new();
350 let s = POLY_SUBPIXEL_SCALE as i32;
351
352 clip.move_to(0, 0);
353 clip.line_to(&mut ras, 10 * s, 10 * s);
354 ras.sort_cells();
355
356 assert!(ras.total_cells() > 0);
357 }
358
359 #[test]
360 fn test_clip_int_visible_line() {
361 let mut clip = RasterizerSlClipInt::new();
362 let s = POLY_SUBPIXEL_SCALE as i32;
363 clip.clip_box(0, 0, 100 * s, 100 * s);
364
365 let mut ras = RasterizerCellsAa::new();
366 clip.move_to(10 * s, 10 * s);
367 clip.line_to(&mut ras, 50 * s, 50 * s);
368 ras.sort_cells();
369
370 assert!(ras.total_cells() > 0);
371 assert!(ras.min_x() >= 10);
372 assert!(ras.max_x() <= 50);
373 }
374
375 #[test]
376 fn test_clip_int_fully_clipped_by_y() {
377 let mut clip = RasterizerSlClipInt::new();
378 let s = POLY_SUBPIXEL_SCALE as i32;
379 clip.clip_box(0, 10 * s, 100 * s, 90 * s);
380
381 let mut ras = RasterizerCellsAa::new();
382 clip.move_to(10 * s, 0);
384 clip.line_to(&mut ras, 50 * s, 5 * s);
385 ras.sort_cells();
386
387 assert_eq!(ras.total_cells(), 0);
388 }
389
390 #[test]
391 fn test_clip_int_clipped_by_x_right() {
392 let mut clip = RasterizerSlClipInt::new();
393 let s = POLY_SUBPIXEL_SCALE as i32;
394 clip.clip_box(0, 0, 50 * s, 100 * s);
395
396 let mut ras = RasterizerCellsAa::new();
397 clip.move_to(10 * s, 10 * s);
398 clip.line_to(&mut ras, 80 * s, 80 * s);
399 ras.sort_cells();
400
401 assert!(ras.total_cells() > 0);
402 for cell in ras.cells() {
404 assert!(cell.x <= 50, "Cell x={} exceeds clip x2=50", cell.x);
405 }
406 }
407
408 #[test]
409 fn test_clip_int_reset_clipping() {
410 let mut clip = RasterizerSlClipInt::new();
411 let s = POLY_SUBPIXEL_SCALE as i32;
412 clip.clip_box(0, 0, 10 * s, 10 * s);
413 assert!(clip.clipping);
414 clip.reset_clipping();
415 assert!(!clip.clipping);
416 }
417
418 #[test]
419 fn test_clip_int_move_to_d() {
420 let mut clip = RasterizerSlClipInt::new();
421 clip.move_to_d(10.5, 20.5);
422 assert_eq!(clip.x1, upscale(10.5));
423 assert_eq!(clip.y1, upscale(20.5));
424 }
425
426 #[test]
427 fn test_clip_int_line_to_d() {
428 let mut clip = RasterizerSlClipInt::new();
429 let mut ras = RasterizerCellsAa::new();
430 clip.move_to_d(0.0, 0.0);
431 clip.line_to_d(&mut ras, 10.0, 10.0);
432 ras.sort_cells();
433 assert!(ras.total_cells() > 0);
434 }
435
436 #[test]
441 fn test_no_clip_passthrough() {
442 let mut clip = RasterizerSlNoClip::new();
443 let mut ras = RasterizerCellsAa::new();
444 let s = POLY_SUBPIXEL_SCALE as i32;
445
446 clip.move_to(0, 0);
447 clip.line_to(&mut ras, 10 * s, 10 * s);
448 ras.sort_cells();
449
450 assert!(ras.total_cells() > 0);
451 }
452
453 #[test]
454 fn test_no_clip_double_api() {
455 let mut clip = RasterizerSlNoClip::new();
456 let mut ras = RasterizerCellsAa::new();
457
458 clip.move_to_d(0.0, 0.0);
459 clip.line_to_d(&mut ras, 5.0, 5.0);
460 ras.sort_cells();
461
462 assert!(ras.total_cells() > 0);
463 }
464
465 #[test]
466 fn test_poly_coord() {
467 assert_eq!(poly_coord(1.0), POLY_SUBPIXEL_SCALE as i32);
468 assert_eq!(poly_coord(0.0), 0);
469 }
470}