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_simple_pie_fill          PORTABLE C      */
35 /*                                                           6.1          */
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_utility_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 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
82 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
83 /*                                            resulting in version 6.1    */
84 /*                                                                        */
85 /**************************************************************************/
86 #if defined(GX_ARC_DRAWING_SUPPORT)
87 
_gx_display_driver_generic_simple_pie_fill(GX_DRAW_CONTEXT * context,INT xcenter,INT ycenter,UINT r,INT start_angle,INT end_angle,GX_BOOL skip_end)88 VOID _gx_display_driver_generic_simple_pie_fill(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter,
89                                                 UINT r, INT start_angle, INT end_angle, GX_BOOL skip_end)
90 {
91 /* The function will only fill a pie with both start angle and end angle are
92    between 0 and 180 or beween 180 and 360.*/
93 
94 GX_DISPLAY           *display;
95 GX_BRUSH             *brush;
96 GX_RECTANGLE         *clip;
97 GX_RECTANGLE          arc_clip[4];
98 GX_POINT              point;
99 GX_POINT              points[3];
100 INT                   sign[4][2] = {{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
101 INT                  *pLineEnds;
102 GX_POINT             *pGet;
103 INT                   ymin;
104 INT                   ymax;
105 INT                   xstart;
106 INT                   xend;
107 INT                   ystart;
108 INT                   yend;
109 INT                   curx;
110 INT                   cury;
111 INT                   nextx;
112 INT                   nexty;
113 INT                   dx;
114 INT                   dy;
115 INT                   Index;
116 INT                   loop;
117 INT                   height;
118 INT                   xsign;
119 INT                   ysign;
120 INT                   decision;
121 int                   fillingwards;
122 VOID                  (*line_draw)(GX_DRAW_CONTEXT *context, INT x1, INT x2, INT ypos, INT width, GX_COLOR color);
123 INT                   xpos = 0;
124 GX_PIXELMAP          *pixelmap = GX_NULL;
125 GX_VALUE              format;
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_horizontal_line_draw;
132 
133     if (brush -> gx_brush_style & GX_BRUSH_PIXELMAP_FILL)
134     {
135         /* Pick up pixelmap. */
136         pixelmap = brush -> gx_brush_pixelmap;
137         if (pixelmap == GX_NULL)
138         {
139             return;
140         }
141         if (pixelmap -> gx_pixelmap_height <= 0 ||
142             pixelmap -> gx_pixelmap_width <= 0)
143         {
144             return;
145         }
146 
147         memset(&info, 0, sizeof(GX_FILL_PIXELMAP_INFO));
148         format = display -> gx_display_color_format;
149 
150         /*Check the pixelmap format is supported in this driver or not.*/
151         if (format >= GX_COLOR_FORMAT_24XRGB)
152         {
153             /*32ARGB FORMAT use 24xrgb driver for now. So this is a special case.*/
154             if (pixelmap -> gx_pixelmap_format < GX_COLOR_FORMAT_24XRGB)
155             {
156                 /* Display driver only support its native format pixelmap. */
157                 /* Nothing should be drawn if pixelmap format isn't support. */
158                 return;
159             }
160         }
161         else
162         {
163             if (pixelmap -> gx_pixelmap_format != format)
164             {
165                 /* Display driver only support its native format pixelmap. */
166                 /* Nothing should be drawn if pixelmap format isn't support. */
167                 return;
168             }
169             else if (pixelmap -> gx_pixelmap_format == GX_COLOR_FORMAT_4BIT_GRAY)
170             {
171                 info.mask = 0xf0;
172             }
173         }
174 
175         info.pixelmap = pixelmap;
176         info.current_pixel_ptr = (GX_UBYTE *)pixelmap -> gx_pixelmap_data;
177         if (pixelmap -> gx_pixelmap_aux_data_size)
178         {
179             info.current_aux_ptr = (GX_UBYTE *)pixelmap -> gx_pixelmap_aux_data;
180         }
181     }
182 
183     pGet = points;
184 
185     _gx_display_driver_arc_clipping_get(xcenter, ycenter, r, start_angle, end_angle,
186                                         &arc_clip[0], &arc_clip[1], &arc_clip[2], &arc_clip[3]);
187 
188     if ((start_angle <= 180) && (end_angle <= 180))
189     {
190         /* Pie is in upper side. */
191         ymin = ycenter - (INT)r;
192         ymax = ycenter;
193 
194         if (skip_end)
195         {
196             ymax--;
197         }
198     }
199     else
200     {
201         /* Pie is in lower side. */
202         ymin = ycenter;
203         ymax = ycenter + (INT)r;
204     }
205 
206     clip = context -> gx_draw_context_clip;
207 
208     if (clip -> gx_rectangle_top > ymin)
209     {
210         ymin = clip -> gx_rectangle_top;
211     }
212     skip_line = ymin - (ycenter - (INT)r);
213 
214     if (clip -> gx_rectangle_bottom < ymax)
215     {
216         ymax = clip -> gx_rectangle_bottom;
217     }
218 
219     height = ymax - ymin + 1;
220 
221     pLineEnds = _gx_system_scratchpad;
222 
223     /* default the point array to being off the screen on both sides: */
224 
225     for (loop = 0; loop < height * 2; loop += 2)
226     {
227         pLineEnds[loop] = 2000;
228         pLineEnds[loop + 1] = 0;
229     }
230 
231     curx = 0;
232     cury = (INT)r;
233     decision = 5 - (INT)(4 * r);
234 
235     while (curx <= cury)
236     {
237         for (loop = 0; loop < 4; loop++)
238         {
239             point.gx_point_x = (GX_VALUE)(curx * sign[loop][0] + xcenter);
240             point.gx_point_y = (GX_VALUE)(cury * sign[loop][1] + ycenter);
241 
242             if ((point.gx_point_y >= ymin) && (point.gx_point_y <= ymax))
243             {
244                 if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
245                     _gx_utility_rectangle_point_detect(&arc_clip[1], point))
246                 {
247                     Index = (point.gx_point_y - ymin) << 1;
248                     if (point.gx_point_x < pLineEnds[Index])
249                     {
250                         pLineEnds[Index] = point.gx_point_x;
251                     }
252 
253                     if (point.gx_point_x > pLineEnds[Index + 1])
254                     {
255                         pLineEnds[Index + 1] = point.gx_point_x;
256                     }
257                 }
258             }
259 
260             point.gx_point_x = (GX_VALUE)(cury * sign[loop][0] + xcenter);
261             point.gx_point_y = (GX_VALUE)(curx * sign[loop][1] + ycenter);
262 
263             if ((point.gx_point_y >= ymin) && (point.gx_point_y <= ymax))
264             {
265                 if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
266                     _gx_utility_rectangle_point_detect(&arc_clip[1], point))
267                 {
268                     Index = (point.gx_point_y - ymin) << 1;
269                     if (point.gx_point_x < pLineEnds[Index])
270                     {
271                         pLineEnds[Index] = point.gx_point_x;
272                     }
273 
274                     if (point.gx_point_x > pLineEnds[Index + 1])
275                     {
276                         pLineEnds[Index + 1] = point.gx_point_x;
277                     }
278                 }
279             }
280         }
281 
282         if (decision < 0)
283         {
284             decision += 8 * curx + 12;
285         }
286         else
287         {
288             decision += 8 * (curx - cury) + 20;
289             cury--;
290         }
291         curx++;
292     }
293 
294     /* Fill in the point array by using Breshenhams line for
295        2 lines of circle sector
296      */
297 
298     points[1].gx_point_x = (GX_VALUE)xcenter;
299     points[1].gx_point_y = (GX_VALUE)ycenter;
300 
301     _gx_utility_circle_point_get(xcenter, ycenter, r, start_angle, &points[0]);
302     _gx_utility_circle_point_get(xcenter, ycenter, r, end_angle, &points[2]);
303 
304     for (loop = 0; loop < 2; loop++)
305     {
306         xstart = pGet -> gx_point_x;
307         ystart = pGet -> gx_point_y;
308         pGet++;
309         xend = pGet -> gx_point_x;
310         yend = pGet -> gx_point_y;
311         dx = GX_ABS(xend - xstart);
312         dy = GX_ABS(yend - ystart);
313 
314         /* Horizontal Line. */
315         if (ystart == yend)
316         {
317             continue;
318         }
319 
320         /* Vertical Line. */
321         if (xstart == xend)
322         {
323             if (ystart > yend)
324             {
325                 GX_SWAP_VALS(xstart, xend);
326                 GX_SWAP_VALS(ystart, yend);
327             }
328 
329             for (cury = ystart; cury <= yend; cury++)
330             {
331                 if ((cury >= ymin) && (cury <= ymax))
332                 {
333                     Index = (cury - ymin) << 1;
334                     if (xstart <= pLineEnds[Index])
335                     {
336                         pLineEnds[Index] = xstart;
337                     }
338 
339                     if (xstart > pLineEnds[Index + 1])
340                     {
341                         pLineEnds[Index + 1] = xstart;
342                     }
343                 }
344             }
345             continue;
346         }
347 
348         /* Simple Line. */
349         if (((dx >= dy && (xstart > xend)) ||
350              ((dy > dx) && ystart > yend)))
351         {
352             GX_SWAP_VALS(xend, xstart);
353             GX_SWAP_VALS(yend, ystart);
354         }
355 
356         xsign = (xend - xstart) / dx;
357         ysign = (yend - ystart) / dy;
358 
359         if (start_angle < 180)
360         {
361             if (loop == 0)
362             {
363                 fillingwards = (1 + ysign) >> 1;
364             }
365             else
366             {
367                 fillingwards = (1 - ysign) >> 1;
368             }
369         }
370         else
371         {
372             if (loop == 0)
373             {
374                 fillingwards = (1 - ysign) >> 1;
375             }
376             else
377             {
378                 fillingwards = (1 + ysign) >> 1;
379             }
380         }
381 
382         if (dx >= dy)
383         {
384             for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
385                  decision = (dx >> 1); curx <= nextx; curx++, nextx--,
386                  decision += dy)
387             {
388                 if (decision >= dx)
389                 {
390                     decision -= dx;
391                     cury += ysign;
392                     nexty -= ysign;
393                 }
394 
395                 if ((cury - 1 + fillingwards >= ymin) && (cury - 1 + fillingwards <= ymax))
396                 {
397                     Index = (cury - 1 + fillingwards - ymin) << 1;
398 
399                     if (curx < pLineEnds[Index])
400                     {
401                         pLineEnds[Index] = curx;
402                     }
403 
404                     if (curx > pLineEnds[Index + 1])
405                     {
406                         pLineEnds[Index + 1] = curx;
407                     }
408                 }
409 
410                 if ((nexty - 1 + fillingwards >= ymin) && (nexty - 1 + fillingwards <= ymax))
411                 {
412                     Index = (nexty - 1 + fillingwards - ymin) << 1;
413 
414                     if (nextx < pLineEnds[Index])
415                     {
416                         pLineEnds[Index] = nextx;
417                     }
418 
419                     if (nextx > pLineEnds[Index + 1])
420                     {
421                         pLineEnds[Index + 1] = nextx;
422                     }
423                 }
424             }
425         }
426         else
427         {
428             for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
429                  decision = (dy >> 1); cury <= nexty; cury++, nexty--,
430                  decision += dx)
431             {
432                 if (decision >= dy)
433                 {
434                     decision -= dy;
435                     curx += xsign;
436                     nextx -= xsign;
437                 }
438 
439                 if ((cury >= ymin) && (cury <= ymax))
440                 {
441                     Index = (cury - ymin) << 1;
442 
443                     if (curx < pLineEnds[Index])
444                     {
445                         pLineEnds[Index] = curx;
446                     }
447 
448                     if (curx - 1 > pLineEnds[Index + 1])
449                     {
450                         pLineEnds[Index + 1] = curx - 1;
451                     }
452                 }
453 
454                 if ((nexty >= ymin) && (nexty <= ymax))
455                 {
456                     Index = (nexty - ymin) << 1;
457 
458                     if (nextx < pLineEnds[Index])
459                     {
460                         pLineEnds[Index] = nextx;
461                     }
462 
463                     if (nextx - 1 > pLineEnds[Index + 1])
464                     {
465                         pLineEnds[Index + 1] = nextx - 1;
466                     }
467                 }
468             }
469         }
470     }
471 
472     if (pixelmap != NULL)
473     {
474         /* Calculate the draw_start position and skip line to fill the pie area. */
475         xpos = xcenter - (INT)r;
476 
477         /*Skip the un-draw line.*/
478         if (skip_line > 0)
479         {
480             skip_line %= info.pixelmap -> gx_pixelmap_height;
481             info.draw = GX_FALSE;
482             while (skip_line--)
483             {
484                 display -> gx_display_driver_horizontal_pixelmap_line_draw(context, 0, 0, cury, &info);
485             }
486         }
487     }
488 
489     /* Filling circle sector with horizontal line. */
490     Index = 0;
491     for (cury = ymin; cury <= ymax; cury++)
492     {
493         if (pLineEnds[Index] <= pLineEnds[Index + 1])
494         {
495             if (pLineEnds[Index] < clip -> gx_rectangle_left)
496             {
497                 pLineEnds[Index] = clip -> gx_rectangle_left;
498             }
499 
500             if (pLineEnds[Index + 1] > clip -> gx_rectangle_right)
501             {
502                 pLineEnds[Index + 1] = clip -> gx_rectangle_right;
503             }
504 
505             if (pixelmap)
506             {
507                 info.draw = GX_TRUE;
508                 info.x_offset = pLineEnds[Index] - xpos;
509                 /* Filling pie area with pixelmap. */
510                 display -> gx_display_driver_horizontal_pixelmap_line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], cury, &info);
511             }
512             else
513             {
514                 line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], cury, 1,
515                           brush -> gx_brush_fill_color);
516             }
517         }
518         else
519         {
520             if (pixelmap != GX_NULL)
521             {
522                 info.draw = GX_FALSE;
523                 display -> gx_display_driver_horizontal_pixelmap_line_draw(context, 0, 0, cury, &info);
524             }
525         }
526 
527         Index += 2;
528     }
529 }
530 
531 #endif
532 
533