1use crate::pixfmt_rgba::PixelFormat;
10use crate::rasterizer_scanline_aa::{RasterizerScanlineAa, Scanline};
11use crate::renderer_base::RendererBase;
12use crate::scanline_u::ScanlineU8;
13use crate::span_allocator::SpanAllocator;
14
15pub fn render_scanlines_aa_solid<PF: PixelFormat>(
29 ras: &mut RasterizerScanlineAa,
30 sl: &mut ScanlineU8,
31 ren: &mut RendererBase<PF>,
32 color: &PF::ColorType,
33) {
34 if !ras.rewind_scanlines() {
35 return;
36 }
37
38 sl.reset(ras.min_x(), ras.max_x());
39 while ras.sweep_scanline(sl) {
40 render_scanline_aa_solid_u8(sl, ren, color);
41 }
42}
43
44fn render_scanline_aa_solid_u8<PF: PixelFormat>(
49 sl: &ScanlineU8,
50 ren: &mut RendererBase<PF>,
51 color: &PF::ColorType,
52) {
53 let y = sl.y();
54 let spans = sl.begin();
55 let covers = sl.covers();
56
57 for span in spans {
58 let x = span.x;
59 let len = span.len;
60 if len > 0 {
61 ren.blend_solid_hspan(
62 x,
63 y,
64 len,
65 color,
66 &covers[span.cover_offset..span.cover_offset + len as usize],
67 );
68 }
69 }
72}
73
74pub struct RendererScanlineAaSolid<'a, PF: PixelFormat> {
83 ren: &'a mut RendererBase<PF>,
84 color: PF::ColorType,
85}
86
87impl<'a, PF: PixelFormat> RendererScanlineAaSolid<'a, PF>
88where
89 PF::ColorType: Default,
90{
91 pub fn new(ren: &'a mut RendererBase<PF>) -> Self {
92 Self {
93 ren,
94 color: PF::ColorType::default(),
95 }
96 }
97
98 pub fn color(&mut self, c: PF::ColorType) {
99 self.color = c;
100 }
101
102 pub fn render(&mut self, ras: &mut RasterizerScanlineAa, sl: &mut ScanlineU8) {
104 render_scanlines_aa_solid(ras, sl, self.ren, &self.color);
105 }
106}
107
108pub trait SpanGenerator {
120 type Color;
121
122 fn prepare(&mut self);
124
125 fn generate(&mut self, span: &mut [Self::Color], x: i32, y: i32, len: u32);
129}
130
131pub fn render_scanlines_aa<PF, SG>(
143 ras: &mut RasterizerScanlineAa,
144 sl: &mut ScanlineU8,
145 ren: &mut RendererBase<PF>,
146 alloc: &mut SpanAllocator<SG::Color>,
147 span_gen: &mut SG,
148) where
149 PF: PixelFormat<ColorType = SG::Color>,
150 SG: SpanGenerator,
151 SG::Color: Default + Clone,
152{
153 if !ras.rewind_scanlines() {
154 return;
155 }
156
157 sl.reset(ras.min_x(), ras.max_x());
158 span_gen.prepare();
159 while ras.sweep_scanline(sl) {
160 render_scanline_aa(sl, ren, alloc, span_gen);
161 }
162}
163
164fn render_scanline_aa<PF, SG>(
168 sl: &ScanlineU8,
169 ren: &mut RendererBase<PF>,
170 alloc: &mut SpanAllocator<SG::Color>,
171 span_gen: &mut SG,
172) where
173 PF: PixelFormat<ColorType = SG::Color>,
174 SG: SpanGenerator,
175 SG::Color: Default + Clone,
176{
177 let y = sl.y();
178 let spans = sl.begin();
179 let covers = sl.covers();
180
181 for span in spans {
182 let x = span.x;
183 let len = span.len.unsigned_abs() as usize;
184
185 let colors = alloc.allocate(len);
186 span_gen.generate(colors, x, y, len as u32);
187
188 if span.len < 0 {
189 let cover = covers[span.cover_offset];
191 ren.blend_color_hspan(x, y, len as i32, colors, &[], cover);
192 } else {
193 let span_covers = &covers[span.cover_offset..span.cover_offset + len];
195 let first_cover = span_covers[0];
196 ren.blend_color_hspan(x, y, len as i32, colors, span_covers, first_cover);
197 }
198 }
199}
200
201#[cfg(test)]
206mod tests {
207 use super::*;
208 use crate::basics::POLY_SUBPIXEL_SCALE;
209 use crate::color::Rgba8;
210 use crate::ellipse::Ellipse;
211 use crate::path_storage::PathStorage;
212 use crate::pixfmt_rgba::{PixelFormat, PixfmtRgba32};
213 use crate::rendering_buffer::RowAccessor;
214
215 const BPP: usize = 4;
216
217 fn make_rgba_buffer(w: u32, h: u32) -> (Vec<u8>, RowAccessor) {
218 let stride = (w * BPP as u32) as i32;
219 let buf = vec![255u8; (h * w * BPP as u32) as usize]; let mut ra = RowAccessor::new();
221 unsafe {
222 ra.attach(buf.as_ptr() as *mut u8, w, h, stride);
223 }
224 (buf, ra)
225 }
226
227 #[test]
232 fn test_render_triangle_solid_red() {
233 let (_buf, mut ra) = make_rgba_buffer(100, 100);
234 let mut pf = PixfmtRgba32::new(&mut ra);
235 pf.clear(&Rgba8::new(255, 255, 255, 255));
236 let mut ren = RendererBase::new(pf);
237 let mut ras = RasterizerScanlineAa::new();
238 let mut sl = ScanlineU8::new();
239
240 let s = POLY_SUBPIXEL_SCALE as i32;
242 ras.move_to(20 * s, 20 * s);
243 ras.line_to(80 * s, 20 * s);
244 ras.line_to(50 * s, 80 * s);
245
246 let red = Rgba8::new(255, 0, 0, 255);
247 render_scanlines_aa_solid(&mut ras, &mut sl, &mut ren, &red);
248
249 let center = ren.ren().pixel(50, 40);
251 assert_eq!(center.r, 255, "Center R should be 255");
252 assert_eq!(center.g, 0, "Center G should be 0");
253 assert_eq!(center.b, 0, "Center B should be 0");
254 assert_eq!(center.a, 255, "Center A should be 255");
255
256 let corner = ren.ren().pixel(0, 0);
258 assert_eq!(corner.r, 255);
259 assert_eq!(corner.g, 255);
260 assert_eq!(corner.b, 255);
261
262 let edge = ren.ren().pixel(20, 20);
265 assert!(edge.r > 0, "Edge pixel should have some red: r={}", edge.r);
267 }
268
269 #[test]
274 fn test_render_rectangle() {
275 let (_buf, mut ra) = make_rgba_buffer(100, 100);
276 let mut pf = PixfmtRgba32::new(&mut ra);
277 pf.clear(&Rgba8::new(255, 255, 255, 255));
278 let mut ren = RendererBase::new(pf);
279 let mut ras = RasterizerScanlineAa::new();
280 let mut sl = ScanlineU8::new();
281
282 ras.move_to_d(10.0, 10.0);
284 ras.line_to_d(90.0, 10.0);
285 ras.line_to_d(90.0, 90.0);
286 ras.line_to_d(10.0, 90.0);
287
288 let blue = Rgba8::new(0, 0, 255, 255);
289 render_scanlines_aa_solid(&mut ras, &mut sl, &mut ren, &blue);
290
291 let center = ren.ren().pixel(50, 50);
293 assert_eq!(center.b, 255);
294 assert_eq!(center.r, 0);
295
296 let outside = ren.ren().pixel(5, 5);
298 assert_eq!(outside.r, 255);
299 assert_eq!(outside.g, 255);
300 }
301
302 #[test]
307 fn test_render_ellipse() {
308 let (_buf, mut ra) = make_rgba_buffer(100, 100);
309 let mut pf = PixfmtRgba32::new(&mut ra);
310 pf.clear(&Rgba8::new(0, 0, 0, 255)); let mut ren = RendererBase::new(pf);
312 let mut ras = RasterizerScanlineAa::new();
313 let mut sl = ScanlineU8::new();
314
315 let mut ellipse = Ellipse::new(50.0, 50.0, 30.0, 30.0, 64, false);
316 ras.add_path(&mut ellipse, 0);
317
318 let green = Rgba8::new(0, 255, 0, 255);
319 render_scanlines_aa_solid(&mut ras, &mut sl, &mut ren, &green);
320
321 let center = ren.ren().pixel(50, 50);
323 assert_eq!(center.g, 255);
324
325 let corner = ren.ren().pixel(0, 0);
327 assert_eq!(corner.g, 0);
328 }
329
330 #[test]
335 fn test_render_path_storage_triangle() {
336 let (_buf, mut ra) = make_rgba_buffer(100, 100);
337 let mut pf = PixfmtRgba32::new(&mut ra);
338 pf.clear(&Rgba8::new(255, 255, 255, 255));
339 let mut ren = RendererBase::new(pf);
340 let mut ras = RasterizerScanlineAa::new();
341 let mut sl = ScanlineU8::new();
342
343 let mut path = PathStorage::new();
344 path.move_to(10.0, 10.0);
345 path.line_to(90.0, 50.0);
346 path.line_to(50.0, 90.0);
347 ras.add_path(&mut path, 0);
350
351 let magenta = Rgba8::new(255, 0, 255, 255);
352 render_scanlines_aa_solid(&mut ras, &mut sl, &mut ren, &magenta);
353
354 let p = ren.ren().pixel(40, 50);
356 assert!(p.r > 0 || p.b > 0, "Center should have color");
357 }
358
359 #[test]
364 fn test_render_with_clip_box() {
365 let (_buf, mut ra) = make_rgba_buffer(100, 100);
366 let mut pf = PixfmtRgba32::new(&mut ra);
367 pf.clear(&Rgba8::new(255, 255, 255, 255));
368 let mut ren = RendererBase::new(pf);
369 let mut ras = RasterizerScanlineAa::new();
370 let mut sl = ScanlineU8::new();
371
372 ras.clip_box(0.0, 0.0, 50.0, 50.0);
374
375 ras.move_to_d(10.0, 10.0);
377 ras.line_to_d(90.0, 10.0);
378 ras.line_to_d(90.0, 90.0);
379 ras.line_to_d(10.0, 90.0);
380
381 let red = Rgba8::new(255, 0, 0, 255);
382 render_scanlines_aa_solid(&mut ras, &mut sl, &mut ren, &red);
383
384 let inside = ren.ren().pixel(30, 30);
386 assert_eq!(inside.r, 255);
387
388 let outside = ren.ren().pixel(70, 70);
390 assert_eq!(outside.r, 255);
391 assert_eq!(outside.g, 255);
392 }
393
394 #[test]
399 fn test_renderer_scanline_aa_solid_wrapper() {
400 let (_buf, mut ra) = make_rgba_buffer(100, 100);
401 let mut pf = PixfmtRgba32::new(&mut ra);
402 pf.clear(&Rgba8::new(0, 0, 0, 255));
403 let mut ren = RendererBase::new(pf);
404 let mut ras = RasterizerScanlineAa::new();
405 let mut sl = ScanlineU8::new();
406
407 ras.move_to_d(20.0, 20.0);
408 ras.line_to_d(80.0, 20.0);
409 ras.line_to_d(50.0, 80.0);
410
411 let mut renderer = RendererScanlineAaSolid::new(&mut ren);
412 renderer.color(Rgba8::new(0, 255, 0, 255));
413 renderer.render(&mut ras, &mut sl);
414
415 let center = renderer.ren.ren().pixel(50, 40);
417 assert_eq!(center.g, 255);
418 }
419
420 #[test]
425 fn test_render_empty() {
426 let (_buf, mut ra) = make_rgba_buffer(10, 10);
427 let mut pf = PixfmtRgba32::new(&mut ra);
428 pf.clear(&Rgba8::new(255, 255, 255, 255));
429 let mut ren = RendererBase::new(pf);
430 let mut ras = RasterizerScanlineAa::new();
431 let mut sl = ScanlineU8::new();
432
433 let red = Rgba8::new(255, 0, 0, 255);
435 render_scanlines_aa_solid(&mut ras, &mut sl, &mut ren, &red);
436
437 let p = ren.ren().pixel(5, 5);
439 assert_eq!(p.r, 255);
440 assert_eq!(p.g, 255);
441 }
442
443 #[test]
448 fn test_render_gradient_rectangle() {
449 use crate::gradient_lut::GradientLinearColor;
450 use crate::span_gradient::{GradientX, SpanGradient};
451 use crate::span_interpolator_linear::SpanInterpolatorLinear;
452 use crate::trans_affine::TransAffine;
453
454 let (_buf, mut ra) = make_rgba_buffer(100, 100);
455 let mut pf = PixfmtRgba32::new(&mut ra);
456 pf.clear(&Rgba8::new(255, 255, 255, 255));
457 let mut ren = RendererBase::new(pf);
458 let mut ras = RasterizerScanlineAa::new();
459 let mut sl = ScanlineU8::new();
460
461 ras.move_to_d(10.0, 10.0);
463 ras.line_to_d(90.0, 10.0);
464 ras.line_to_d(90.0, 90.0);
465 ras.line_to_d(10.0, 90.0);
466
467 let trans = TransAffine::new();
469 let interp = SpanInterpolatorLinear::new(trans);
470 let gc = GradientLinearColor::new(
471 Rgba8::new(0, 0, 0, 255),
472 Rgba8::new(255, 255, 255, 255),
473 256,
474 );
475 let mut sg = SpanGradient::new(interp, GradientX, &gc, 10.0, 90.0);
476 let mut alloc = SpanAllocator::<Rgba8>::new();
477
478 render_scanlines_aa(&mut ras, &mut sl, &mut ren, &mut alloc, &mut sg);
479
480 let left = ren.ren().pixel(15, 50);
482 assert!(left.r < 50, "Left r={} should be dark", left.r);
483
484 let right = ren.ren().pixel(85, 50);
486 assert!(right.r > 200, "Right r={} should be light", right.r);
487
488 let mid = ren.ren().pixel(50, 50);
490 assert!(
491 mid.r > 50 && mid.r < 200,
492 "Mid r={} should be between",
493 mid.r
494 );
495
496 let outside = ren.ren().pixel(5, 5);
498 assert_eq!(outside.r, 255);
499 }
500
501 #[test]
506 fn test_render_gouraud_triangle() {
507 use crate::span_gouraud_rgba::SpanGouraudRgba;
508
509 let (_buf, mut ra) = make_rgba_buffer(100, 100);
510 let mut pf = PixfmtRgba32::new(&mut ra);
511 pf.clear(&Rgba8::new(0, 0, 0, 0)); let mut ren = RendererBase::new(pf);
513 let mut ras = RasterizerScanlineAa::new();
514 let mut sl = ScanlineU8::new();
515
516 let mut gouraud = SpanGouraudRgba::new_with_triangle(
518 Rgba8::new(255, 0, 0, 255), Rgba8::new(0, 255, 0, 255), Rgba8::new(0, 0, 255, 255), 10.0,
522 10.0,
523 90.0,
524 10.0,
525 50.0,
526 90.0,
527 0.0,
528 );
529
530 ras.add_path(&mut gouraud, 0);
532
533 let mut alloc = SpanAllocator::<Rgba8>::new();
535 render_scanlines_aa(&mut ras, &mut sl, &mut ren, &mut alloc, &mut gouraud);
536
537 let center = ren.ren().pixel(50, 40);
539 assert!(
540 center.a > 0,
541 "Center should be visible: rgba=({},{},{},{})",
542 center.r,
543 center.g,
544 center.b,
545 center.a
546 );
547
548 let outside = ren.ren().pixel(0, 0);
550 assert_eq!(outside.a, 0, "Outside should be transparent");
551 }
552
553 #[test]
558 fn test_render_gradient_with_lut() {
559 use crate::gradient_lut::GradientLut;
560 use crate::span_gradient::{GradientX, SpanGradient};
561 use crate::span_interpolator_linear::SpanInterpolatorLinear;
562 use crate::trans_affine::TransAffine;
563
564 let (_buf, mut ra) = make_rgba_buffer(100, 50);
565 let mut pf = PixfmtRgba32::new(&mut ra);
566 pf.clear(&Rgba8::new(0, 0, 0, 255));
567 let mut ren = RendererBase::new(pf);
568 let mut ras = RasterizerScanlineAa::new();
569 let mut sl = ScanlineU8::new();
570
571 ras.move_to_d(0.0, 0.0);
573 ras.line_to_d(100.0, 0.0);
574 ras.line_to_d(100.0, 50.0);
575 ras.line_to_d(0.0, 50.0);
576
577 let mut lut = GradientLut::new_default();
579 lut.add_color(0.0, Rgba8::new(255, 0, 0, 255));
580 lut.add_color(0.5, Rgba8::new(0, 255, 0, 255));
581 lut.add_color(1.0, Rgba8::new(0, 0, 255, 255));
582 lut.build_lut();
583
584 let trans = TransAffine::new();
585 let interp = SpanInterpolatorLinear::new(trans);
586 let mut sg = SpanGradient::new(interp, GradientX, &lut, 0.0, 100.0);
587 let mut alloc = SpanAllocator::<Rgba8>::new();
588
589 render_scanlines_aa(&mut ras, &mut sl, &mut ren, &mut alloc, &mut sg);
590
591 let left = ren.ren().pixel(5, 25);
593 assert!(left.r > 200, "Left r={} should be red", left.r);
594
595 let mid = ren.ren().pixel(50, 25);
597 assert!(mid.g > 100, "Mid g={} should be green", mid.g);
598
599 let right = ren.ren().pixel(95, 25);
601 assert!(right.b > 200, "Right b={} should be blue", right.b);
602 }
603}