1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** GUIX Component */
16 /** */
17 /** Display Management (Display) */
18 /** */
19 /**************************************************************************/
20
21 #define GX_SOURCE_CODE
22
23
24 /* Include necessary system files. */
25
26 #include "gx_api.h"
27 #include "gx_system.h"
28 #include "gx_utility.h"
29 #include "gx_display.h"
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* _gx_display_driver_generic_rotated_simple_pie_fill PORTABLE C */
35 /* 6.1.5 */
36 /* AUTHOR */
37 /* */
38 /* Kenneth Maxwell, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* Display driver to fill a pie chart. */
43 /* */
44 /* INPUT */
45 /* */
46 /* context Drawing context */
47 /* xcenter x-coord of center of circle */
48 /* ycenter y-coord of center of circle */
49 /* r Radius of circle */
50 /* start_angle Starting angle */
51 /* end_angle Ending angle */
52 /* */
53 /* OUTPUT */
54 /* */
55 /* None */
56 /* */
57 /* CALLS */
58 /* */
59 /* _gx_display_driver_arc_clipping_get Get an arc clipping. */
60 /* _gx_utility_rectangle_overlap_detect Detects two rectangles being */
61 /* overlap */
62 /* _gx_utility_rectangle_point_detect Detect whether a pixel is */
63 /* inside rectangle */
64 /* _gx_display_driver_circle_point_get Get point coord on a circle */
65 /* [gx_display_driver_horizontal_pixelmap_line_draw] */
66 /* Basic display driver */
67 /* horizontal pixelmap line */
68 /* draw function */
69 /* [gx_display_driver_horizontal_line_draw] */
70 /* Basic display driver */
71 /* horizontal line draw routine*/
72 /* */
73 /* CALLED BY */
74 /* */
75 /* GUIX Internal Code */
76 /* */
77 /* RELEASE HISTORY */
78 /* */
79 /* DATE NAME DESCRIPTION */
80 /* */
81 /* 12-31-2020 Kenneth Maxwell Initial Version 6.1.3 */
82 /* 03-02-2021 Ting Zhu Modified comment(s), */
83 /* improved logic, */
84 /* resulting in version 6.1.5 */
85 /* */
86 /**************************************************************************/
87 #if defined(GX_ARC_DRAWING_SUPPORT)
88
_gx_display_driver_generic_rotated_simple_pie_fill(GX_DRAW_CONTEXT * context,INT xcenter,INT ycenter,UINT r,INT start_angle,INT end_angle,GX_BOOL skip_end)89 static VOID _gx_display_driver_generic_rotated_simple_pie_fill(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter,
90 UINT r, INT start_angle, INT end_angle, GX_BOOL skip_end)
91 {
92 /* The function will only fill a pie with both start angle and end angle are
93 between 0 and 180 or beween 180 and 360.*/
94
95 GX_DISPLAY *display;
96 GX_BRUSH *brush;
97 GX_RECTANGLE *clip;
98 GX_RECTANGLE arc_clip[4];
99 GX_POINT point;
100 GX_POINT points[3];
101 INT sign[4][2] = {{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
102 INT *pLineEnds;
103 GX_POINT *pGet;
104 INT xmin;
105 INT xmax;
106 INT xstart;
107 INT xend;
108 INT ystart;
109 INT yend;
110 INT curx;
111 INT cury;
112 INT nextx;
113 INT nexty;
114 INT dx;
115 INT dy;
116 INT Index;
117 INT loop;
118 INT width;
119 INT xsign;
120 INT ysign;
121 INT decision;
122 int fillingwards;
123 VOID (*line_draw)(GX_DRAW_CONTEXT *context, INT x1, INT x2, INT ypos, INT width, GX_COLOR color);
124 INT xpos = 0;
125 GX_PIXELMAP *pixelmap = GX_NULL;
126 INT skip_line;
127 GX_FILL_PIXELMAP_INFO info;
128
129 display = context -> gx_draw_context_display;
130 brush = &context -> gx_draw_context_brush;
131 line_draw = display -> gx_display_driver_vertical_line_draw;
132
133 if (brush -> gx_brush_style & GX_BRUSH_PIXELMAP_FILL)
134 {
135 if (brush -> gx_brush_pixelmap == GX_NULL)
136 {
137 return;
138 }
139
140 /* Pick up brush pixelmap. */
141 pixelmap = brush -> gx_brush_pixelmap;
142
143 if (pixelmap -> gx_pixelmap_format != display -> gx_display_color_format)
144 {
145 /* Display driver only support its native format pixelmap.*/
146 /* Nothing should be drawn if pixelmap format isn't support. */
147 return;
148 }
149
150 memset(&info, 0, sizeof(GX_FILL_PIXELMAP_INFO));
151
152 info.pixelmap = pixelmap;
153 info.current_pixel_ptr = (GX_UBYTE *)pixelmap -> gx_pixelmap_data;
154 if (pixelmap -> gx_pixelmap_aux_data_size)
155 {
156 info.current_aux_ptr = (GX_UBYTE *)pixelmap -> gx_pixelmap_aux_data;
157 }
158 }
159
160 pGet = points;
161
162 points[1].gx_point_x = (GX_VALUE)xcenter;
163 points[1].gx_point_y = (GX_VALUE)ycenter;
164
165 _gx_utility_circle_point_get(xcenter, ycenter, r, start_angle, &points[0]);
166 _gx_utility_circle_point_get(xcenter, ycenter, r, end_angle, &points[2]);
167
168 _gx_display_driver_arc_clipping_get(xcenter, ycenter, r, start_angle, end_angle,
169 &arc_clip[0], &arc_clip[1], &arc_clip[2], &arc_clip[3]);
170
171 /* Pie is in left side. */
172 xmin = points[0].gx_point_x;
173 xmax = points[2].gx_point_x;
174
175 if (xmin > xmax)
176 {
177 GX_SWAP_VALS(xmin, xmax);
178 }
179
180 if (xmax < xcenter)
181 {
182 xmax = xcenter;
183 }
184 else if (xmin > xcenter)
185 {
186 xmin = xcenter;
187 }
188
189 clip = context -> gx_draw_context_clip;
190
191 if (clip -> gx_rectangle_left > xmin)
192 {
193 xmin = clip -> gx_rectangle_left;
194 }
195
196 if (clip -> gx_rectangle_right < xmax)
197 {
198 xmax = clip -> gx_rectangle_right;
199 }
200
201 width = xmax - xmin + 1;
202
203 pLineEnds = _gx_system_scratchpad;
204
205 /* default the point array to being off the screen on both sides: */
206
207 for (loop = 0; loop < width * 2; loop += 2)
208 {
209 pLineEnds[loop] = 2000;
210 pLineEnds[loop + 1] = 0;
211 }
212
213 curx = 0;
214 cury = (INT)r;
215 decision = 5 - (INT)(4 * r);
216
217 while (curx <= cury)
218 {
219 for (loop = 0; loop < 4; loop++)
220 {
221 point.gx_point_x = (GX_VALUE)(curx * sign[loop][0] + xcenter);
222 point.gx_point_y = (GX_VALUE)(cury * sign[loop][1] + ycenter);
223
224 if ((point.gx_point_x >= xmin) && (point.gx_point_x <= xmax))
225 {
226 if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
227 _gx_utility_rectangle_point_detect(&arc_clip[1], point))
228 {
229 Index = (point.gx_point_x - xmin) << 1;
230 if (point.gx_point_y < pLineEnds[Index])
231 {
232 pLineEnds[Index] = point.gx_point_y;
233 }
234
235 if (point.gx_point_y > pLineEnds[Index + 1])
236 {
237 pLineEnds[Index + 1] = point.gx_point_y;
238 }
239 }
240 }
241
242 point.gx_point_x = (GX_VALUE)(cury * sign[loop][0] + xcenter);
243 point.gx_point_y = (GX_VALUE)(curx * sign[loop][1] + ycenter);
244
245 if ((point.gx_point_x >= xmin) && (point.gx_point_x <= xmax))
246 {
247 if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
248 _gx_utility_rectangle_point_detect(&arc_clip[1], point))
249 {
250 Index = (point.gx_point_x - xmin) << 1;
251 if (point.gx_point_y < pLineEnds[Index])
252 {
253 pLineEnds[Index] = point.gx_point_y;
254 }
255
256 if (point.gx_point_y > pLineEnds[Index + 1])
257 {
258 pLineEnds[Index + 1] = point.gx_point_y;
259 }
260 }
261 }
262 }
263
264 if (decision < 0)
265 {
266 decision += 8 * curx + 12;
267 }
268 else
269 {
270 decision += 8 * (curx - cury) + 20;
271 cury--;
272 }
273 curx++;
274 }
275
276 /* Fill in the point array by using Breshenhams line for
277 2 lines of circle sector
278 */
279
280 for (loop = 0; loop < 2; loop++)
281 {
282 xstart = pGet -> gx_point_x;
283 ystart = pGet -> gx_point_y;
284 pGet++;
285 xend = pGet -> gx_point_x;
286 yend = pGet -> gx_point_y;
287 dx = GX_ABS(xend - xstart);
288 dy = GX_ABS(yend - ystart);
289
290 /* Vertical Line. */
291 if (xstart == xend)
292 {
293 continue;
294 }
295
296 /* Horizontal Line. */
297 if (ystart == yend)
298 {
299 if (xstart > xend)
300 {
301 GX_SWAP_VALS(xstart, xend);
302 GX_SWAP_VALS(ystart, yend);
303 }
304
305 if (skip_end)
306 {
307 ystart--;
308 }
309
310 for (curx = xstart; curx <= xend; curx++)
311 {
312 if ((curx >= xmin) && (curx <= xmax))
313 {
314 Index = (curx - xmin) << 1;
315 if (ystart < pLineEnds[Index])
316 {
317 pLineEnds[Index] = ystart;
318 }
319
320 if (ystart > pLineEnds[Index + 1])
321 {
322 pLineEnds[Index + 1] = ystart;
323 }
324 }
325 }
326 continue;
327 }
328
329 /* Simple Line. */
330 if (((dx >= dy && (xstart > xend)) ||
331 ((dy > dx) && ystart > yend)))
332 {
333 GX_SWAP_VALS(xend, xstart);
334 GX_SWAP_VALS(yend, ystart);
335 }
336
337 xsign = (xend - xstart) / dx;
338 ysign = (yend - ystart) / dy;
339
340 if (dx >= dy)
341 {
342 for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
343 decision = (dx >> 1); curx <= nextx; curx++, nextx--,
344 decision += dy)
345 {
346 if (decision >= dx)
347 {
348 decision -= dx;
349 cury += ysign;
350 nexty -= ysign;
351 }
352
353 if ((curx >= xmin) && (curx <= xmax))
354 {
355 Index = (curx - xmin) << 1;
356
357 if (cury < pLineEnds[Index])
358 {
359 pLineEnds[Index] = cury;
360 }
361
362 if (cury - 1 > pLineEnds[Index + 1])
363 {
364 pLineEnds[Index + 1] = cury - 1;
365 }
366 }
367
368 if ((nextx >= xmin) && (nextx <= xmax))
369 {
370 Index = (nextx - xmin) << 1;
371
372 if (nexty < pLineEnds[Index])
373 {
374 pLineEnds[Index] = nexty;
375 }
376
377 if (nexty - 1 > pLineEnds[Index + 1])
378 {
379 pLineEnds[Index + 1] = nexty - 1;
380 }
381 }
382 }
383 }
384 else
385 {
386 if (start_angle < 180)
387 {
388 if (loop == 0)
389 {
390 fillingwards = 0;
391 }
392 else
393 {
394 fillingwards = 1;
395 }
396 }
397 else
398 {
399 if (loop == 0)
400 {
401 fillingwards = 1;
402 }
403 else
404 {
405 fillingwards = 0;
406 }
407 }
408
409 for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
410 decision = (dy >> 1); cury <= nexty; cury++, nexty--,
411 decision += dx)
412 {
413 if (decision >= dy)
414 {
415 decision -= dy;
416 curx += xsign;
417 nextx -= xsign;
418 }
419
420 if ((curx - 1 + fillingwards >= xmin) && (curx - 1 + fillingwards <= xmax))
421 {
422 Index = (curx - 1 + fillingwards - xmin) << 1;
423
424 if (cury < pLineEnds[Index])
425 {
426 pLineEnds[Index] = cury;
427 }
428
429 if (cury > pLineEnds[Index + 1])
430 {
431 pLineEnds[Index + 1] = cury;
432 }
433 }
434
435 if ((nextx - 1 + fillingwards >= xmin) && (nextx - 1 + fillingwards <= xmax))
436 {
437 Index = (nextx - 1 + fillingwards - xmin) << 1;
438
439 if (nexty < pLineEnds[Index])
440 {
441 pLineEnds[Index] = nexty;
442 }
443
444 if (nexty > pLineEnds[Index + 1])
445 {
446 pLineEnds[Index + 1] = nexty;
447 }
448 }
449 }
450 }
451 }
452
453 /* Filling circle sector with horizontal line. */
454 if (pixelmap)
455 {
456 if (context -> gx_draw_context_display -> gx_display_rotation_angle == GX_SCREEN_ROTATION_CW)
457 {
458 skip_line = (xmax - (xcenter - (INT)r) + 1) % pixelmap -> gx_pixelmap_width;
459
460 /*Skip the un-draw line.*/
461 if (skip_line)
462 {
463 skip_line = pixelmap -> gx_pixelmap_width - skip_line;
464 }
465
466 Index = (width - 1) << 1;
467 xsign = -1;
468 xstart = xmax;
469 }
470 else
471 {
472 skip_line = (xmin - clip -> gx_rectangle_left);
473
474 Index = 0;
475 xsign = 1;
476 xstart = xmin;
477 }
478
479 /*Skip the un-draw line.*/
480 if (skip_line)
481 {
482 info.draw = GX_FALSE;
483 while (skip_line--)
484 {
485 display -> gx_display_driver_horizontal_pixelmap_line_draw(context, 0, 0, 0, &info);
486 }
487 }
488
489 info.draw = GX_TRUE;
490 xpos = ycenter - (INT)r;
491
492 for (curx = xmin; curx <= xmax; curx++)
493 {
494 if (pLineEnds[Index] < clip -> gx_rectangle_top)
495 {
496 pLineEnds[Index] = clip -> gx_rectangle_top;
497 }
498
499 if (pLineEnds[Index + 1] > clip -> gx_rectangle_bottom)
500 {
501 pLineEnds[Index + 1] = clip -> gx_rectangle_bottom;
502 }
503
504 info.x_offset = pLineEnds[Index] - xpos;
505
506 /* Filling pie area with pixelmap. */
507 display -> gx_display_driver_horizontal_pixelmap_line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], xstart, &info);
508
509 xstart += xsign;
510 Index += xsign;
511 Index += xsign;
512 }
513 }
514 else
515 {
516 Index = 0;
517 for (curx = xmin; curx <= xmax; curx++)
518 {
519 if (pLineEnds[Index] < clip -> gx_rectangle_top)
520 {
521 pLineEnds[Index] = clip -> gx_rectangle_top;
522 }
523
524 if (pLineEnds[Index + 1] > clip -> gx_rectangle_bottom)
525 {
526 pLineEnds[Index + 1] = clip -> gx_rectangle_bottom;
527 }
528
529 if (pLineEnds[Index] <= pLineEnds[Index + 1])
530 {
531 line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], curx, 1,
532 brush -> gx_brush_fill_color);
533 }
534
535 Index += 2;
536 }
537 }
538 }
539
540 /**************************************************************************/
541 /* */
542 /* FUNCTION RELEASE */
543 /* */
544 /* _gx_display_driver_generic_rotated_pie_fill PORTABLE C */
545 /* 6.1.3 */
546 /* AUTHOR */
547 /* */
548 /* Kenneth Maxwell, Microsoft Corporation */
549 /* */
550 /* DESCRIPTION */
551 /* */
552 /* Display driver to fill a pie. */
553 /* */
554 /* INPUT */
555 /* */
556 /* context Drawing context */
557 /* xcenter x-coord of center of circle */
558 /* ycenter y-coord of center of circle */
559 /* r Radius of circle */
560 /* start_angle The start angle of circle arc */
561 /* end_angle The end angle of circle arc */
562 /* */
563 /* OUTPUT */
564 /* */
565 /* None */
566 /* */
567 /* CALLS */
568 /* */
569 /* _gx_display_driver_generic_simple_pie_fill */
570 /* Real display driver draw */
571 /* filled-pie function */
572 /* */
573 /* CALLED BY */
574 /* */
575 /* _gx_canvas_pie_draw */
576 /* */
577 /* RELEASE HISTORY */
578 /* */
579 /* DATE NAME DESCRIPTION */
580 /* */
581 /* 12-31-2020 Kenneth Maxwell Initial Version 6.1.3 */
582 /* */
583 /**************************************************************************/
_gx_display_driver_generic_rotated_pie_fill(GX_DRAW_CONTEXT * context,INT xcenter,INT ycenter,UINT r,INT start_angle,INT end_angle)584 VOID _gx_display_driver_generic_rotated_pie_fill(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter, UINT r, INT start_angle, INT end_angle)
585 {
586 /* The function fills a pie.*/
587
588
589 if (start_angle < 180)
590 {
591 if (end_angle < 180)
592 {
593 _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, start_angle, end_angle, GX_FALSE);
594 }
595 else if (end_angle < 360)
596 {
597 /* Skip-end parameter should only be set when drawing the above area.
598 It would be set to GX_TRUE to skip the bottom line to avoid case that this line will be drawn twice, which
599 is not correct, when brush alpha is set. */
600 _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, start_angle, 180, GX_TRUE);
601 _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, 180, end_angle, GX_FALSE);
602 }
603 else
604 {
605 _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, start_angle, 180, GX_TRUE);
606 _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, 180, 360, GX_FALSE);
607 _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, 0, end_angle - 360, GX_TRUE);
608 }
609 }
610 else
611 {
612 if (end_angle < 360)
613 {
614 _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, start_angle, end_angle, GX_FALSE);
615 }
616 else if (end_angle < 540)
617 {
618 _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, start_angle, 360, GX_FALSE);
619 _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, 0, end_angle - 360, GX_TRUE);
620 }
621 else
622 {
623 _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, start_angle, 360, GX_FALSE);
624 _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, 0, 180, GX_TRUE);
625 _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, 180, end_angle - 360, GX_FALSE);
626 }
627 }
628 }
629
630 #endif
631
632