1use crate::basics::{iround, COVER_FULL};
7use crate::dda_line::{self, LineBresenhamInterpolator};
8use crate::ellipse_bresenham::EllipseBresenhamInterpolator;
9use crate::pixfmt_rgba::PixelFormat;
10use crate::renderer_base::RendererBase;
11
12pub struct RendererPrimitives<'a, PF: PixelFormat> {
24 ren: &'a mut RendererBase<PF>,
25 fill_color: PF::ColorType,
26 line_color: PF::ColorType,
27 curr_x: i32,
28 curr_y: i32,
29}
30
31impl<'a, PF: PixelFormat> RendererPrimitives<'a, PF>
32where
33 PF::ColorType: Default + Clone,
34{
35 pub fn new(ren: &'a mut RendererBase<PF>) -> Self {
36 Self {
37 ren,
38 fill_color: PF::ColorType::default(),
39 line_color: PF::ColorType::default(),
40 curr_x: 0,
41 curr_y: 0,
42 }
43 }
44
45 pub fn coord(c: f64) -> i32 {
47 iround(c * dda_line::SUBPIXEL_SCALE as f64)
48 }
49
50 pub fn set_fill_color(&mut self, c: PF::ColorType) {
51 self.fill_color = c;
52 }
53
54 pub fn set_line_color(&mut self, c: PF::ColorType) {
55 self.line_color = c;
56 }
57
58 pub fn fill_color(&self) -> &PF::ColorType {
59 &self.fill_color
60 }
61
62 pub fn line_color(&self) -> &PF::ColorType {
63 &self.line_color
64 }
65
66 pub fn rectangle(&mut self, x1: i32, y1: i32, x2: i32, y2: i32) {
68 self.ren
69 .blend_hline(x1, y1, x2 - 1, &self.line_color.clone(), COVER_FULL);
70 self.ren
71 .blend_vline(x2, y1, y2 - 1, &self.line_color.clone(), COVER_FULL);
72 self.ren
73 .blend_hline(x1 + 1, y2, x2, &self.line_color.clone(), COVER_FULL);
74 self.ren
75 .blend_vline(x1, y1 + 1, y2, &self.line_color.clone(), COVER_FULL);
76 }
77
78 pub fn solid_rectangle(&mut self, x1: i32, y1: i32, x2: i32, y2: i32) {
80 self.ren
81 .blend_bar(x1, y1, x2, y2, &self.fill_color.clone(), COVER_FULL);
82 }
83
84 pub fn outlined_rectangle(&mut self, x1: i32, y1: i32, x2: i32, y2: i32) {
86 self.rectangle(x1, y1, x2, y2);
87 self.ren.blend_bar(
88 x1 + 1,
89 y1 + 1,
90 x2 - 1,
91 y2 - 1,
92 &self.fill_color.clone(),
93 COVER_FULL,
94 );
95 }
96
97 pub fn ellipse(&mut self, x: i32, y: i32, rx: i32, ry: i32) {
99 let mut ei = EllipseBresenhamInterpolator::new(rx, ry);
100 let mut dx = 0i32;
101 let mut dy = -ry;
102
103 loop {
104 ei.next();
105 dx += ei.dx();
106 dy += ei.dy();
107 let lc = self.line_color.clone();
108 self.ren.blend_pixel(x + dx, y + dy, &lc, COVER_FULL);
109 self.ren.blend_pixel(x + dx, y - dy, &lc, COVER_FULL);
110 self.ren.blend_pixel(x - dx, y - dy, &lc, COVER_FULL);
111 self.ren.blend_pixel(x - dx, y + dy, &lc, COVER_FULL);
112 if dy >= 0 {
113 break;
114 }
115 }
116 }
117
118 pub fn solid_ellipse(&mut self, x: i32, y: i32, rx: i32, ry: i32) {
120 let mut ei = EllipseBresenhamInterpolator::new(rx, ry);
121 let mut dx = 0i32;
122 let mut dy = -ry;
123 let mut dy0 = dy;
124 let mut dx0 = dx;
125
126 loop {
127 ei.next();
128 dx += ei.dx();
129 dy += ei.dy();
130
131 if dy != dy0 {
132 let fc = self.fill_color.clone();
133 self.ren
134 .blend_hline(x - dx0, y + dy0, x + dx0, &fc, COVER_FULL);
135 self.ren
136 .blend_hline(x - dx0, y - dy0, x + dx0, &fc, COVER_FULL);
137 }
138 dx0 = dx;
139 dy0 = dy;
140 if dy >= 0 {
141 break;
142 }
143 }
144 let fc = self.fill_color.clone();
145 self.ren
146 .blend_hline(x - dx0, y + dy0, x + dx0, &fc, COVER_FULL);
147 }
148
149 pub fn outlined_ellipse(&mut self, x: i32, y: i32, rx: i32, ry: i32) {
151 let mut ei = EllipseBresenhamInterpolator::new(rx, ry);
152 let mut dx = 0i32;
153 let mut dy = -ry;
154
155 loop {
156 ei.next();
157 dx += ei.dx();
158 dy += ei.dy();
159
160 let lc = self.line_color.clone();
161 self.ren.blend_pixel(x + dx, y + dy, &lc, COVER_FULL);
162 self.ren.blend_pixel(x + dx, y - dy, &lc, COVER_FULL);
163 self.ren.blend_pixel(x - dx, y - dy, &lc, COVER_FULL);
164 self.ren.blend_pixel(x - dx, y + dy, &lc, COVER_FULL);
165
166 if ei.dy() != 0 && dx != 0 {
167 let fc = self.fill_color.clone();
168 self.ren
169 .blend_hline(x - dx + 1, y + dy, x + dx - 1, &fc, COVER_FULL);
170 self.ren
171 .blend_hline(x - dx + 1, y - dy, x + dx - 1, &fc, COVER_FULL);
172 }
173 if dy >= 0 {
174 break;
175 }
176 }
177 }
178
179 pub fn line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, last: bool) {
183 let mut li = LineBresenhamInterpolator::new(x1, y1, x2, y2);
184
185 let mut len = li.len();
186 if len == 0 {
187 if last {
188 let lc = self.line_color.clone();
189 self.ren.blend_pixel(
190 dda_line::line_lr(x1),
191 dda_line::line_lr(y1),
192 &lc,
193 COVER_FULL,
194 );
195 }
196 return;
197 }
198
199 if last {
200 len += 1;
201 }
202
203 if li.is_ver() {
204 for _ in 0..len {
205 let lc = self.line_color.clone();
206 self.ren.blend_pixel(li.x2(), li.y1(), &lc, COVER_FULL);
207 li.vstep();
208 }
209 } else {
210 for _ in 0..len {
211 let lc = self.line_color.clone();
212 self.ren.blend_pixel(li.x1(), li.y2(), &lc, COVER_FULL);
213 li.hstep();
214 }
215 }
216 }
217
218 pub fn move_to(&mut self, x: i32, y: i32) {
220 self.curr_x = x;
221 self.curr_y = y;
222 }
223
224 pub fn line_to(&mut self, x: i32, y: i32, last: bool) {
226 self.line(self.curr_x, self.curr_y, x, y, last);
227 self.curr_x = x;
228 self.curr_y = y;
229 }
230
231 pub fn ren(&self) -> &RendererBase<PF> {
232 self.ren
233 }
234
235 pub fn ren_mut(&mut self) -> &mut RendererBase<PF> {
236 self.ren
237 }
238}
239
240impl<'a, PF: PixelFormat> crate::rasterizer_outline::RendererPrimitivesLike
241 for RendererPrimitives<'a, PF>
242where
243 PF::ColorType: Default + Clone,
244{
245 type Color = PF::ColorType;
246
247 fn coord(c: f64) -> i32 {
248 Self::coord(c)
249 }
250
251 fn move_to(&mut self, x: i32, y: i32) {
252 self.move_to(x, y);
253 }
254
255 fn line_to(&mut self, x: i32, y: i32, last: bool) {
256 self.line_to(x, y, last);
257 }
258
259 fn set_line_color(&mut self, c: Self::Color) {
260 self.set_line_color(c);
261 }
262}
263
264#[cfg(test)]
269mod tests {
270 use super::*;
271 use crate::color::Rgba8;
272 use crate::pixfmt_rgba::PixfmtRgba32;
273 use crate::rendering_buffer::RowAccessor;
274
275 fn make_ren(w: u32, h: u32) -> (Vec<u8>, RowAccessor) {
276 let stride = (w * 4) as i32;
277 let buf = vec![0u8; (w * h * 4) as usize];
278 let mut ra = RowAccessor::new();
279 unsafe { ra.attach(buf.as_ptr() as *mut u8, w, h, stride) };
280 (buf, ra)
281 }
282
283 #[test]
284 fn test_rectangle() {
285 let (_buf, mut ra) = make_ren(20, 20);
286 let pf = PixfmtRgba32::new(&mut ra);
287 let mut rb = RendererBase::new(pf);
288 let mut prim = RendererPrimitives::new(&mut rb);
289 prim.set_line_color(Rgba8::new(255, 0, 0, 255));
290 prim.rectangle(2, 2, 8, 8);
291 }
292
293 #[test]
294 fn test_solid_rectangle() {
295 let (_buf, mut ra) = make_ren(20, 20);
296 let pf = PixfmtRgba32::new(&mut ra);
297 let mut rb = RendererBase::new(pf);
298 let mut prim = RendererPrimitives::new(&mut rb);
299 prim.set_fill_color(Rgba8::new(0, 255, 0, 255));
300 prim.solid_rectangle(3, 3, 6, 6);
301 }
302
303 #[test]
304 fn test_ellipse() {
305 let (_buf, mut ra) = make_ren(30, 30);
306 let pf = PixfmtRgba32::new(&mut ra);
307 let mut rb = RendererBase::new(pf);
308 let mut prim = RendererPrimitives::new(&mut rb);
309 prim.set_line_color(Rgba8::new(0, 0, 255, 255));
310 prim.ellipse(15, 15, 5, 5);
311 }
312
313 #[test]
314 fn test_solid_ellipse() {
315 let (_buf, mut ra) = make_ren(30, 30);
316 let pf = PixfmtRgba32::new(&mut ra);
317 let mut rb = RendererBase::new(pf);
318 let mut prim = RendererPrimitives::new(&mut rb);
319 prim.set_fill_color(Rgba8::new(255, 255, 0, 255));
320 prim.solid_ellipse(15, 15, 5, 5);
321 }
322
323 #[test]
324 fn test_line() {
325 let (_buf, mut ra) = make_ren(20, 20);
326 let pf = PixfmtRgba32::new(&mut ra);
327 let mut rb = RendererBase::new(pf);
328 let mut prim = RendererPrimitives::new(&mut rb);
329 prim.set_line_color(Rgba8::new(255, 0, 0, 255));
330 let x1 = RendererPrimitives::<PixfmtRgba32>::coord(2.0);
331 let y1 = RendererPrimitives::<PixfmtRgba32>::coord(5.0);
332 let x2 = RendererPrimitives::<PixfmtRgba32>::coord(10.0);
333 let y2 = RendererPrimitives::<PixfmtRgba32>::coord(5.0);
334 prim.line(x1, y1, x2, y2, true);
335 }
336
337 #[test]
338 fn test_move_to_line_to() {
339 let (_buf, mut ra) = make_ren(20, 20);
340 let pf = PixfmtRgba32::new(&mut ra);
341 let mut rb = RendererBase::new(pf);
342 let mut prim = RendererPrimitives::new(&mut rb);
343 prim.set_line_color(Rgba8::new(255, 255, 255, 255));
344 let x1 = RendererPrimitives::<PixfmtRgba32>::coord(1.0);
345 let y1 = RendererPrimitives::<PixfmtRgba32>::coord(1.0);
346 prim.move_to(x1, y1);
347 let x2 = RendererPrimitives::<PixfmtRgba32>::coord(10.0);
348 let y2 = RendererPrimitives::<PixfmtRgba32>::coord(1.0);
349 prim.line_to(x2, y2, true);
350 }
351
352 #[test]
353 fn test_color_accessors() {
354 let (_buf, mut ra) = make_ren(10, 10);
355 let pf = PixfmtRgba32::new(&mut ra);
356 let mut rb = RendererBase::new(pf);
357 let mut prim = RendererPrimitives::new(&mut rb);
358 prim.set_fill_color(Rgba8::new(10, 20, 30, 40));
359 prim.set_line_color(Rgba8::new(50, 60, 70, 80));
360 assert_eq!(prim.fill_color().r, 10);
361 assert_eq!(prim.line_color().r, 50);
362 }
363
364 #[test]
365 fn test_outlined_rectangle() {
366 let (_buf, mut ra) = make_ren(20, 20);
367 let pf = PixfmtRgba32::new(&mut ra);
368 let mut rb = RendererBase::new(pf);
369 let mut prim = RendererPrimitives::new(&mut rb);
370 prim.set_line_color(Rgba8::new(255, 0, 0, 255));
371 prim.set_fill_color(Rgba8::new(0, 255, 0, 255));
372 prim.outlined_rectangle(2, 2, 8, 8);
373 }
374}