1use core::cell::Cell;
4use core::cmp;
5
6#[cfg(feature = "std")]
7use crate::blur;
8use crate::color::Color;
9use crate::graphicspath::GraphicsPath;
10use crate::graphicspath::PointType;
11use crate::Mode;
12
13pub trait Renderer {
16 fn width(&self) -> u32;
18
19 fn height(&self) -> u32;
21
22 fn data(&self) -> &[Color];
24
25 fn data_mut(&mut self) -> &mut [Color];
27
28 fn sync(&mut self) -> bool;
30
31 fn update(&mut self) -> bool;
33
34 fn update_rects(&mut self, rects: &[(i32, i32, u32, u32)]) -> bool;
36
37 fn mode(&self) -> &Cell<Mode>;
39
40 fn pixel(&mut self, x: i32, y: i32, color: Color) {
43 let replace = match self.mode().get() {
44 Mode::Blend => false,
45 Mode::Overwrite => true,
46 };
47 let w = self.width() as i32;
48 let h = self.height() as i32;
49 let data = self.data_mut();
50
51 if x >= 0 && y >= 0 && x < w && y < h {
52 let new = color.data;
53 let alpha = (new >> 24) & 0xFF;
54 let old = &mut data[(y * w + x) as usize].data;
55
56 if alpha >= 255 || replace {
57 *old = new;
58 } else if alpha > 0 {
59 let n_alpha = 255 - alpha;
60 let rb = ((n_alpha * (*old & 0x00FF00FF)) + (alpha * (new & 0x00FF00FF))) >> 8;
61 let ag = (n_alpha * ((*old & 0xFF00FF00) >> 8))
62 + (alpha * (0x01000000 | ((new & 0x0000FF00) >> 8)));
63
64 *old = (rb & 0x00FF00FF) | (ag & 0xFF00FF00);
65 }
66 }
67 }
68
69 fn arc(&mut self, x0: i32, y0: i32, radius: i32, parts: u8, color: Color) {
71 let mut x = radius.abs();
72 let mut y = 0;
73 let mut err = 0;
74
75 #[allow(clippy::comparison_chain)]
77 while x >= y {
78 if radius < 0 {
79 if parts & 1 << 0 != 0 {
80 self.rect(x0 - x, y0 + y, x as u32, 1, color);
81 }
82 if parts & 1 << 1 != 0 {
83 self.rect(x0, y0 + y, x as u32 + 1, 1, color);
84 }
85 if parts & 1 << 2 != 0 {
86 self.rect(x0 - y, y0 + x, y as u32, 1, color);
87 }
88 if parts & 1 << 3 != 0 {
89 self.rect(x0, y0 + x, y as u32 + 1, 1, color);
90 }
91 if parts & 1 << 4 != 0 {
92 self.rect(x0 - x, y0 - y, x as u32, 1, color);
93 }
94 if parts & 1 << 5 != 0 {
95 self.rect(x0, y0 - y, x as u32 + 1, 1, color);
96 }
97 if parts & 1 << 6 != 0 {
98 self.rect(x0 - y, y0 - x, y as u32, 1, color);
99 }
100 if parts & 1 << 7 != 0 {
101 self.rect(x0, y0 - x, y as u32 + 1, 1, color);
102 }
103 } else if radius == 0 {
104 self.pixel(x0, y0, color);
105 } else {
106 if parts & 1 << 0 != 0 {
107 self.pixel(x0 - x, y0 + y, color);
108 }
109 if parts & 1 << 1 != 0 {
110 self.pixel(x0 + x, y0 + y, color);
111 }
112 if parts & 1 << 2 != 0 {
113 self.pixel(x0 - y, y0 + x, color);
114 }
115 if parts & 1 << 3 != 0 {
116 self.pixel(x0 + y, y0 + x, color);
117 }
118 if parts & 1 << 4 != 0 {
119 self.pixel(x0 - x, y0 - y, color);
120 }
121 if parts & 1 << 5 != 0 {
122 self.pixel(x0 + x, y0 - y, color);
123 }
124 if parts & 1 << 6 != 0 {
125 self.pixel(x0 - y, y0 - x, color);
126 }
127 if parts & 1 << 7 != 0 {
128 self.pixel(x0 + y, y0 - x, color);
129 }
130 }
131
132 y += 1;
133 err += 1 + 2 * y;
134 if 2 * (err - x) + 1 > 0 {
135 x -= 1;
136 err += 1 - 2 * x;
137 }
138 }
139 }
140
141 fn circle(&mut self, x0: i32, y0: i32, radius: i32, color: Color) {
143 let mut x = radius.abs();
144 let mut y = 0;
145 let mut err = -radius.abs();
146
147 match radius {
148 radius if radius > 0 => {
149 err = 0;
150 while x >= y {
151 self.pixel(x0 - x, y0 + y, color);
152 self.pixel(x0 + x, y0 + y, color);
153 self.pixel(x0 - y, y0 + x, color);
154 self.pixel(x0 + y, y0 + x, color);
155 self.pixel(x0 - x, y0 - y, color);
156 self.pixel(x0 + x, y0 - y, color);
157 self.pixel(x0 - y, y0 - x, color);
158 self.pixel(x0 + y, y0 - x, color);
159
160 y += 1;
161 err += 1 + 2 * y;
162 if 2 * (err - x) + 1 > 0 {
163 x -= 1;
164 err += 1 - 2 * x;
165 }
166 }
167 }
168
169 radius if radius < 0 => {
170 while x >= y {
171 let lasty = y;
172 err += y;
173 y += 1;
174 err += y;
175 self.line4points(x0, y0, x, lasty, color);
176 if err >= 0 {
177 if x != lasty {
178 self.line4points(x0, y0, lasty, x, color);
179 }
180 err -= x;
181 x -= 1;
182 err -= x;
183 }
184 }
185 }
186 _ => {
187 self.pixel(x0, y0, color);
188 }
189 }
190 }
191
192 fn line4points(&mut self, x0: i32, y0: i32, x: i32, y: i32, color: Color) {
193 self.rect(x0 - x, y0 + y, x as u32 * 2 + 1, 1, color);
195 if y != 0 {
196 self.rect(x0 - x, y0 - y, x as u32 * 2 + 1, 1, color);
198 }
199 }
200
201 fn line(&mut self, argx1: i32, argy1: i32, argx2: i32, argy2: i32, color: Color) {
203 let mut x = argx1;
204 let mut y = argy1;
205
206 let dx = if argx1 > argx2 {
207 argx1 - argx2
208 } else {
209 argx2 - argx1
210 };
211 let dy = if argy1 > argy2 {
212 argy1 - argy2
213 } else {
214 argy2 - argy1
215 };
216
217 let sx = if argx1 < argx2 { 1 } else { -1 };
218 let sy = if argy1 < argy2 { 1 } else { -1 };
219
220 let mut err = if dx > dy { dx } else { -dy } / 2;
221 let mut err_tolerance;
222
223 loop {
224 self.pixel(x, y, color);
225
226 if x == argx2 && y == argy2 {
227 break;
228 };
229
230 err_tolerance = 2 * err;
231
232 if err_tolerance > -dx {
233 err -= dy;
234 x += sx;
235 }
236 if err_tolerance < dy {
237 err += dx;
238 y += sy;
239 }
240 }
241 }
242
243 fn lines(&mut self, points: &[[i32; 2]], color: Color) {
244 if points.is_empty() {
245 } else if points.len() == 1 {
247 self.pixel(points[0][0], points[0][1], color);
248 } else {
249 for i in 0..points.len() - 1 {
250 self.line(
251 points[i][0],
252 points[i][1],
253 points[i + 1][0],
254 points[i + 1][1],
255 color,
256 );
257 }
258 }
259 }
260
261 fn draw_path_stroke(&mut self, graphicspath: GraphicsPath, color: Color) {
263 let mut x: i32 = 0;
264 let mut y: i32 = 0;
265
266 for point in graphicspath.points {
267 if let PointType::Connect = point.2 {
268 self.line(x, y, point.0, point.1, color)
269 }
270 x = point.0;
271 y = point.1;
272 }
273 }
274
275 #[cfg(feature = "unifont")]
277 fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
278 let mut offset = (c as usize) * 16;
279 for row in 0..16 {
280 let row_data = if offset < crate::FONT.len() {
281 crate::FONT[offset]
282 } else {
283 0
284 };
285
286 for col in 0..8 {
287 let pixel = (row_data >> (7 - col)) & 1;
288 if pixel > 0 {
289 self.pixel(x + col, y + row, color);
290 }
291 }
292 offset += 1;
293 }
294 }
295
296 fn set(&mut self, color: Color) {
298 let data = self.data_mut();
299 let data_ptr = data.as_mut_ptr();
300 for i in 0..data.len() as isize {
301 unsafe { *data_ptr.offset(i) = color }
302 }
303 }
304
305 fn clear(&mut self) {
307 self.set(Color::rgb(0, 0, 0));
308 }
309
310 fn rect(&mut self, x: i32, y: i32, w: u32, h: u32, color: Color) {
311 let replace = match self.mode().get() {
312 Mode::Blend => false,
313 Mode::Overwrite => true,
314 };
315 let self_w = self.width();
316 let self_h = self.height();
317
318 let start_y = cmp::max(0, cmp::min(self_h as i32 - 1, y));
319 let end_y = cmp::max(start_y, cmp::min(self_h as i32, y + h as i32));
320
321 let start_x = cmp::max(0, cmp::min(self_w as i32 - 1, x));
322 let len = cmp::max(start_x, cmp::min(self_w as i32, x + w as i32)) - start_x;
323
324 let alpha = (color.data >> 24) & 0xFF;
325 if alpha >= 255 || replace {
327 let data = self.data_mut();
328 let data_ptr = data.as_mut_ptr();
329 for y in start_y..end_y {
330 let start = (y * self_w as i32 + start_x) as isize;
331 let end = start + len as isize;
332 for i in start..end {
333 unsafe {
334 *data_ptr.offset(i) = color;
335 }
336 }
337 }
338 } else {
339 for y in start_y..end_y {
340 for x in start_x..start_x + len {
341 self.pixel(x, y, color);
342 }
343 }
344 }
345 }
347
348 #[cfg(feature = "std")]
349 fn box_blur(&mut self, x: i32, y: i32, w: u32, h: u32, r: i32) {
350 let self_w = self.width();
351 let self_h = self.height();
352
353 let start_y = cmp::max(0, cmp::min(self_h as i32 - 1, y));
354 let end_y = cmp::max(start_y, cmp::min(self_h as i32, y + h as i32));
355
356 let start_x = cmp::max(0, cmp::min(self_w as i32 - 1, x));
357 let end_x = cmp::max(start_x, cmp::min(self_w as i32, x + w as i32));
358
359 let data = self.data_mut();
360 let mut blur_data: Vec<Color> = Vec::new();
361 for y in start_y..end_y {
362 for x in start_x..end_x {
363 let old = data[y as usize * self_w as usize + x as usize];
364 blur_data.push(old);
365 }
366 }
367 let real_w = end_x - start_x;
368 let real_h = end_y - start_y;
369 blur::gauss_blur(&mut blur_data, real_w as u32, real_h as u32, r as f32);
370
371 let mut counter: u32 = 0;
372 for y in start_y..end_y {
373 for x in start_x..end_x {
374 let a = blur_data[counter as usize];
375 let old = &mut data[y as usize * self_w as usize + x as usize].data;
376
377 *old = a.data;
378 counter += 1;
379 }
380 }
381 }
382
383 #[allow(clippy::too_many_arguments)]
384 #[cfg(feature = "std")]
385 fn box_shadow(
386 &mut self,
387 x: i32,
388 y: i32,
389 w: u32,
390 h: u32,
391 offset_x: i32,
392 offset_y: i32,
393 r: i32,
394 color: Color,
395 ) {
396 let real_w = w + (2 * r as u32);
397 let real_h = h + (2 * r as u32);
398
399 let mut blur_data: Vec<Color> = Vec::new();
400 for new_x in x..x + real_w as i32 {
401 for new_y in y..y + real_h as i32 {
402 if new_x < x + r
403 || new_y < y + r
404 || new_y >= y + h as i32 + r
405 || new_x >= x + w as i32 + r
406 {
407 blur_data.push(Color::rgb(255, 0, 255));
408 } else {
409 blur_data.push(Color::rgb(0, 0, 0));
410 }
411 }
412 }
413
414 blur::gauss_blur(&mut blur_data, real_w, real_h, r as f32 / 3.0);
415
416 let mut counter: u32 = 0;
417 for new_x in (x - r)..(x + real_w as i32 - r) {
418 for new_y in (y - r)..(y + real_h as i32 - r) {
419 let c = blur_data[counter as usize];
420
421 let alpha: u8 = if color.a() < 255 - c.r() {
422 color.a()
423 } else {
424 255 - c.r()
425 };
426 let col = Color::rgba(color.r(), color.g(), color.b(), alpha);
427
428 let new_x_b = new_x + offset_x;
429 let new_y_b = new_y + offset_y;
430 if new_x_b < x
431 || new_x_b > x + w as i32 - 1
432 || new_y_b < y
433 || new_y_b > y + h as i32 - 1
434 {
435 self.pixel(new_x_b, new_y_b, col);
436 }
437 counter += 1;
438 }
439 }
440 }
441
442 fn image(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color]) {
444 match self.mode().get() {
445 Mode::Blend => self.image_fast(start_x, start_y, w, h, data),
446 Mode::Overwrite => self.image_opaque(start_x, start_y, w, h, data),
447 }
448 }
449
450 #[inline(always)]
452 fn image_legacy(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color]) {
453 let mut i = 0;
454 for y in start_y..start_y + h as i32 {
455 for x in start_x..start_x + w as i32 {
456 if i < data.len() {
457 self.pixel(x, y, data[i])
458 }
459 i += 1;
460 }
461 }
462 }
463
464 fn image_over(&mut self, start: i32, image_data: &[Color]) {
466 let start = start as usize * self.width() as usize;
467 let window_data = self.data_mut();
468 let stop = cmp::min(start + image_data.len(), window_data.len());
469 let end = cmp::min(image_data.len(), window_data.len() - start);
470
471 window_data[start..stop].copy_from_slice(&image_data[..end]);
472 }
473
474 #[inline(always)]
476 fn image_opaque(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, image_data: &[Color]) {
477 let w = w as usize;
478 let mut h = h as usize;
479 let width = self.width() as usize;
480 let height = self.height() as usize;
481 let start_x = start_x as usize;
482 let start_y = start_y as usize;
483
484 if start_x >= width || start_y >= height {
486 return;
487 }
488 if h + start_y > height {
489 h = height - start_y;
490 }
491 let window_data = self.data_mut();
492 let offset = start_y * width + start_x;
493 for l in 0..h {
495 let start = offset + l * width;
496 let mut stop = start + w;
497 let begin = l * w;
498 let mut end = begin + w;
499 if start_x + w > width {
501 stop = (start_y + l + 1) * width - 1;
502 end = begin + stop - start;
503 }
504 window_data[start..stop].copy_from_slice(&image_data[begin..end]);
505 }
506 }
507
508 #[inline(always)]
510 fn image_fast(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, image_data: &[Color]) {
511 let w = w as usize;
512 let h = h as usize;
513 let width = self.width() as usize;
514 let start_x = start_x as usize;
515 let start_y = start_y as usize;
516
517 if start_x >= width || start_y >= self.height() as usize {
519 return;
520 }
521 let window_data = self.data_mut();
522 let offset = start_y * width + start_x;
523
524 for l in 0..h {
526 let start = offset + l * width;
527 let mut stop = start + w;
528 let begin = l * w;
529 let end = begin + w;
530
531 if start_x + w > width {
533 stop = (start_y + l + 1) * width;
534 }
535 let mut k = 0;
536 for i in begin..end {
537 if i < image_data.len() {
538 let new = image_data[i].data;
539 let alpha = (new >> 24) & 0xFF;
540 if alpha > 0 && (start + k) < window_data.len() && (start + k) < stop {
541 let old = &mut window_data[start + k].data;
542 if alpha >= 255 {
543 *old = new;
544 } else {
545 let n_alpha = 255 - alpha;
546 let rb = ((n_alpha * (*old & 0x00FF00FF))
547 + (alpha * (new & 0x00FF00FF)))
548 >> 8;
549 let ag = (n_alpha * ((*old & 0xFF00FF00) >> 8))
550 + (alpha * (0x01000000 | ((new & 0x0000FF00) >> 8)));
551
552 *old = (rb & 0x00FF00FF) | (ag & 0xFF00FF00);
553 }
554 }
555 k += 1;
556 }
557 }
558 }
559 }
560
561 #[allow(clippy::too_many_arguments)]
563 #[cfg(feature = "std")]
564 fn linear_gradient(
565 &mut self,
566 rect_x: i32,
567 rect_y: i32,
568 rect_width: u32,
569 rect_height: u32,
570 start_x: i32,
571 start_y: i32,
572 end_x: i32,
573 end_y: i32,
574 start_color: Color,
575 end_color: Color,
576 ) {
577 fn clamp(proj: f64) -> f64 {
578 if proj < 0.0 {
579 0.0
580 } else if proj > 1.0 {
581 1.0
582 } else {
583 proj
584 }
585 }
586
587 if (start_x == end_x) && (start_y == end_y) {
588 self.rect(rect_x, rect_y, rect_width, rect_height, start_color);
590 } else if start_x == end_x {
591 let y_factor = 1.0 / (end_y - start_y) as f64;
593 for y in rect_y..(rect_y + rect_height as i32) {
594 let proj = (y - start_y) as f64 * y_factor;
595 let scale = clamp(proj);
596 let color = Color::interpolate(start_color, end_color, scale);
597 self.line(rect_x, y, rect_x + rect_width as i32 - 1, y, color);
598 }
599 } else if start_y == end_y {
600 let x_factor = 1.0 / (end_x - start_x) as f64;
602 for x in rect_x..(rect_x + rect_width as i32) {
603 let proj = (x - start_x) as f64 * x_factor;
604 let scale = clamp(proj);
605 let color = Color::interpolate(start_color, end_color, scale);
606 self.line(x, rect_y, x, rect_y + rect_height as i32 - 1, color);
607 }
608 } else {
609 let grad_x = (end_x - start_x) as f64;
612 let grad_y = (end_y - start_y) as f64;
613 let grad_len = 1.0 / (grad_x * grad_x + grad_y * grad_y);
614
615 for y in rect_y..(rect_y + rect_height as i32) {
616 for x in rect_x..(rect_x + rect_width as i32) {
617 let pix_x = (x - start_x) as f64;
619 let pix_y = (y - start_y) as f64;
620 let proj = (pix_x * grad_x + pix_y * grad_y) * grad_len;
622 let scale = clamp(proj);
624 let color = Color::interpolate(start_color, end_color, scale);
626 self.pixel(x, y, color);
627 }
628 }
629 }
630 }
631
632 #[allow(clippy::too_many_arguments)]
634 fn rounded_rect(
635 &mut self,
636 x: i32,
637 y: i32,
638 w: u32,
639 h: u32,
640 radius: u32,
641 filled: bool,
642 color: Color,
643 ) {
644 let w = w as i32;
645 let h = h as i32;
646 let r = radius as i32;
647
648 if filled {
649 self.arc(x + r, y + r, -r, 1 << 4 | 1 << 6, color);
651 self.arc(x + w - 1 - r, y + r, -r, 1 << 5 | 1 << 7, color);
652 self.arc(x + r, y + h - 1 - r, -r, 1 << 0 | 1 << 2, color);
653 self.arc(x + w - 1 - r, y + h - 1 - r, -r, 1 << 1 | 1 << 3, color);
654
655 self.rect(x + r, y, (w - 1 - r * 2) as u32, r as u32 + 1, color);
657 self.rect(
658 x + r,
659 y + h - 1 - r,
660 (w - 1 - r * 2) as u32,
661 r as u32 + 1,
662 color,
663 );
664 self.rect(x, y + r + 1, w as u32, (h - 2 - r * 2) as u32, color);
665 } else {
666 self.arc(x + r, y + r, r, 1 << 4 | 1 << 6, color);
668 self.arc(x + w - 1 - r, y + r, r, 1 << 5 | 1 << 7, color);
669 self.arc(x + r, y + h - 1 - r, r, 1 << 0 | 1 << 2, color);
670 self.arc(x + w - 1 - r, y + h - 1 - r, r, 1 << 1 | 1 << 3, color);
671
672 self.rect(x + r + 1, y, (w - 2 - r * 2) as u32, 1, color);
674 self.rect(x + r + 1, y + h - 1, (w - 2 - r * 2) as u32, 1, color);
675 self.rect(x, y + r + 1, 1, (h - 2 - r * 2) as u32, color);
676 self.rect(x + w - 1, y + r + 1, 1, (h - 2 - r * 2) as u32, color);
677 }
678 }
679
680 #[cfg(feature = "std")]
682 fn wu_line(&mut self, x0: i32, y0: i32, x1: i32, y1: i32, color: Color) {
683 let mut x0 = x0 as f64;
685 let mut y0 = y0 as f64;
686 let mut x1 = x1 as f64;
687 let mut y1 = y1 as f64;
688 let r = color.r();
689 let g = color.g();
690 let b = color.b();
691 let a = color.a() as f64;
692
693 fn ipart(x: f64) -> i32 {
694 x.trunc() as i32
695 }
696
697 fn fpart(x: f64) -> f64 {
698 if x < 0.0 {
699 return 1.0 - (x - x.floor());
700 }
701 x - x.floor()
702 }
703
704 fn rfpart(x: f64) -> f64 {
705 1.0 - fpart(x)
706 }
707
708 fn chkalpha(mut alpha: f64) -> u8 {
709 if alpha > 255.0 {
710 alpha = 255.0
711 };
712 if alpha < 0.0 {
713 alpha = 0.0
714 };
715 alpha as u8
716 }
717
718 let steep: bool = (y1 - y0).abs() > (x1 - x0).abs();
719 let mut temp;
720 if steep {
721 temp = x0;
722 x0 = y0;
723 y0 = temp;
724 temp = x1;
725 x1 = y1;
726 y1 = temp;
727 }
728 if x0 > x1 {
729 temp = x0;
730 x0 = x1;
731 x1 = temp;
732 temp = y0;
733 y0 = y1;
734 y1 = temp;
735 }
736 let dx = x1 - x0;
737 let dy = y1 - y0;
738 let gradient = dy / dx;
739
740 let mut xend: f64 = x0.round();
741 let mut yend: f64 = y0 + gradient * (xend - x0);
742 let mut xgap: f64 = rfpart(x0 + 0.5);
743 let xpixel1 = xend as i32;
744 let ypixel1 = ipart(yend);
745
746 if steep {
747 self.pixel(
748 ypixel1,
749 xpixel1,
750 Color::rgba(r, g, b, chkalpha(rfpart(yend) * xgap * a)),
751 );
752 self.pixel(
753 ypixel1 + 1,
754 xpixel1,
755 Color::rgba(r, g, b, chkalpha(fpart(yend) * xgap * a)),
756 );
757 } else {
758 self.pixel(
759 xpixel1,
760 ypixel1,
761 Color::rgba(r, g, b, chkalpha(rfpart(yend) * xgap * a)),
762 );
763 self.pixel(
764 xpixel1 + 1,
765 ypixel1,
766 Color::rgba(r, g, b, chkalpha(fpart(yend) * xgap * a)),
767 );
768 }
769 let mut intery: f64 = yend + gradient;
770 xend = x1.round();
771 yend = y1 + gradient * (xend - x1);
772 xgap = fpart(x1 + 0.5);
773 let xpixel2 = xend as i32;
774 let ypixel2 = ipart(yend);
775 if steep {
776 self.pixel(
777 ypixel2,
778 xpixel2,
779 Color::rgba(r, g, b, chkalpha(rfpart(yend) * xgap * a)),
780 );
781 self.pixel(
782 ypixel2 + 1,
783 xpixel2,
784 Color::rgba(r, g, b, chkalpha(fpart(yend) * xgap * a)),
785 );
786 } else {
787 self.pixel(
788 xpixel2,
789 ypixel2,
790 Color::rgba(r, g, b, chkalpha(rfpart(yend) * xgap * a)),
791 );
792 self.pixel(
793 xpixel2 + 1,
794 ypixel2,
795 Color::rgba(r, g, b, chkalpha(fpart(yend) * xgap * a)),
796 );
797 }
798 if steep {
799 for x in (xpixel1 + 1)..(xpixel2) {
800 self.pixel(
801 ipart(intery),
802 x,
803 Color::rgba(r, g, b, chkalpha(a * rfpart(intery))),
804 );
805 self.pixel(
806 ipart(intery) + 1,
807 x,
808 Color::rgba(r, g, b, chkalpha(a * fpart(intery))),
809 );
810 intery += gradient;
811 }
812 } else {
813 for x in (xpixel1 + 1)..(xpixel2) {
814 self.pixel(
815 x,
816 ipart(intery),
817 Color::rgba(r, g, b, chkalpha(a * rfpart(intery))),
818 );
819 self.pixel(
820 x,
821 ipart(intery) + 1,
822 Color::rgba(r, g, b, chkalpha(a * fpart(intery))),
823 );
824 intery += gradient;
825 }
826 }
827 }
828
829 #[cfg(feature = "std")]
831 fn wu_circle(&mut self, x0: i32, y0: i32, radius: i32, color: Color) {
832 let r = color.r();
833 let g = color.g();
834 let b = color.b();
835 let a = color.a();
836 let mut y = 0;
837 let mut x = radius;
838 let mut d = 0_f64;
839
840 self.pixel(x0 + x, y0 + y, color);
841 self.pixel(x0 - x, y0 - y, color);
842 self.pixel(x0 + y, y0 - x, color);
843 self.pixel(x0 - y, y0 + x, color);
844
845 while x > y {
846 let di = dist(radius, y);
847 if di < d {
848 x -= 1;
849 }
850 let col = Color::rgba(r, g, b, (a as f64 * (1.0 - di)) as u8);
851 let col2 = Color::rgba(r, g, b, (a as f64 * di) as u8);
852
853 self.pixel(x0 + x, y0 + y, col);
854 self.pixel(x0 + x - 1, y0 + y, col2); self.pixel(x0 - x, y0 + y, col);
856 self.pixel(x0 - x + 1, y0 + y, col2); self.pixel(x0 + x, y0 - y, col);
858 self.pixel(x0 + x - 1, y0 - y, col2); self.pixel(x0 - x, y0 - y, col);
860 self.pixel(x0 - x + 1, y0 - y, col2); self.pixel(x0 + y, y0 + x, col);
863 self.pixel(x0 + y, y0 + x - 1, col2);
864 self.pixel(x0 - y, y0 + x, col);
865 self.pixel(x0 - y, y0 + x - 1, col2);
866 self.pixel(x0 + y, y0 - x, col);
867 self.pixel(x0 + y, y0 - x + 1, col2);
868 self.pixel(x0 - y, y0 - x, col);
869 self.pixel(x0 - y, y0 - x + 1, col2);
870 d = di;
871 y += 1;
872 }
873
874 fn dist(r: i32, y: i32) -> f64 {
875 let x: f64 = ((r * r - y * y) as f64).sqrt();
876 x.ceil() - x
877 }
878 }
879
880 fn getpixel(&self, x: i32, y: i32) -> Color {
882 let p = (self.width() as i32 * y + x) as usize;
883 if p >= self.data().len() {
884 return Color::rgba(0, 0, 0, 0);
885 }
886 self.data()[p]
887 }
888}